1c0c050c5SMichael Chan /* Broadcom NetXtreme-C/E network driver. 2c0c050c5SMichael Chan * 311f15ed3SMichael Chan * Copyright (c) 2014-2016 Broadcom Corporation 48eb992e8SMichael Chan * Copyright (c) 2016-2017 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 11c0c050c5SMichael Chan #include <linux/module.h> 12c0c050c5SMichael Chan #include <linux/pci.h> 13c0c050c5SMichael Chan #include <linux/netdevice.h> 14c0c050c5SMichael Chan #include <linux/if_vlan.h> 15c0c050c5SMichael Chan #include <linux/interrupt.h> 16c0c050c5SMichael Chan #include <linux/etherdevice.h> 17c0c050c5SMichael Chan #include "bnxt_hsi.h" 18c0c050c5SMichael Chan #include "bnxt.h" 192f593846SMichael Chan #include "bnxt_ulp.h" 20c0c050c5SMichael Chan #include "bnxt_sriov.h" 214ab0c6a8SSathya Perla #include "bnxt_vfr.h" 22c0c050c5SMichael Chan #include "bnxt_ethtool.h" 23c0c050c5SMichael Chan 24c0c050c5SMichael Chan #ifdef CONFIG_BNXT_SRIOV 25350a7149SEddie Wai static int bnxt_hwrm_fwd_async_event_cmpl(struct bnxt *bp, 26350a7149SEddie Wai struct bnxt_vf_info *vf, u16 event_id) 27350a7149SEddie Wai { 28350a7149SEddie Wai struct hwrm_fwd_async_event_cmpl_output *resp = bp->hwrm_cmd_resp_addr; 29350a7149SEddie Wai struct hwrm_fwd_async_event_cmpl_input req = {0}; 30350a7149SEddie Wai struct hwrm_async_event_cmpl *async_cmpl; 31350a7149SEddie Wai int rc = 0; 32350a7149SEddie Wai 33350a7149SEddie Wai bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FWD_ASYNC_EVENT_CMPL, -1, -1); 34350a7149SEddie Wai if (vf) 35350a7149SEddie Wai req.encap_async_event_target_id = cpu_to_le16(vf->fw_fid); 36350a7149SEddie Wai else 37350a7149SEddie Wai /* broadcast this async event to all VFs */ 38350a7149SEddie Wai req.encap_async_event_target_id = cpu_to_le16(0xffff); 39350a7149SEddie Wai async_cmpl = (struct hwrm_async_event_cmpl *)req.encap_async_event_cmpl; 4087c374deSMichael Chan async_cmpl->type = cpu_to_le16(ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT); 41350a7149SEddie Wai async_cmpl->event_id = cpu_to_le16(event_id); 42350a7149SEddie Wai 43350a7149SEddie Wai mutex_lock(&bp->hwrm_cmd_lock); 44350a7149SEddie Wai rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 45350a7149SEddie Wai 46350a7149SEddie Wai if (rc) { 47350a7149SEddie Wai netdev_err(bp->dev, "hwrm_fwd_async_event_cmpl failed. rc:%d\n", 48350a7149SEddie Wai rc); 49350a7149SEddie Wai goto fwd_async_event_cmpl_exit; 50350a7149SEddie Wai } 51350a7149SEddie Wai 52350a7149SEddie Wai if (resp->error_code) { 53350a7149SEddie Wai netdev_err(bp->dev, "hwrm_fwd_async_event_cmpl error %d\n", 54350a7149SEddie Wai resp->error_code); 55350a7149SEddie Wai rc = -1; 56350a7149SEddie Wai } 57350a7149SEddie Wai 58350a7149SEddie Wai fwd_async_event_cmpl_exit: 59350a7149SEddie Wai mutex_unlock(&bp->hwrm_cmd_lock); 60350a7149SEddie Wai return rc; 61350a7149SEddie Wai } 62350a7149SEddie Wai 63c0c050c5SMichael Chan static int bnxt_vf_ndo_prep(struct bnxt *bp, int vf_id) 64c0c050c5SMichael Chan { 65caefe526SMichael Chan if (!test_bit(BNXT_STATE_OPEN, &bp->state)) { 66c0c050c5SMichael Chan netdev_err(bp->dev, "vf ndo called though PF is down\n"); 67c0c050c5SMichael Chan return -EINVAL; 68c0c050c5SMichael Chan } 69c0c050c5SMichael Chan if (!bp->pf.active_vfs) { 70c0c050c5SMichael Chan netdev_err(bp->dev, "vf ndo called though sriov is disabled\n"); 71c0c050c5SMichael Chan return -EINVAL; 72c0c050c5SMichael Chan } 7378f30004SVenkat Duvvuru if (vf_id >= bp->pf.active_vfs) { 74c0c050c5SMichael Chan netdev_err(bp->dev, "Invalid VF id %d\n", vf_id); 75c0c050c5SMichael Chan return -EINVAL; 76c0c050c5SMichael Chan } 77c0c050c5SMichael Chan return 0; 78c0c050c5SMichael Chan } 79c0c050c5SMichael Chan 80c0c050c5SMichael Chan int bnxt_set_vf_spoofchk(struct net_device *dev, int vf_id, bool setting) 81c0c050c5SMichael Chan { 82c0c050c5SMichael Chan struct hwrm_func_cfg_input req = {0}; 83c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 84c0c050c5SMichael Chan struct bnxt_vf_info *vf; 85c0c050c5SMichael Chan bool old_setting = false; 86c0c050c5SMichael Chan u32 func_flags; 87c0c050c5SMichael Chan int rc; 88c0c050c5SMichael Chan 898eb992e8SMichael Chan if (bp->hwrm_spec_code < 0x10701) 908eb992e8SMichael Chan return -ENOTSUPP; 918eb992e8SMichael Chan 92c0c050c5SMichael Chan rc = bnxt_vf_ndo_prep(bp, vf_id); 93c0c050c5SMichael Chan if (rc) 94c0c050c5SMichael Chan return rc; 95c0c050c5SMichael Chan 96c0c050c5SMichael Chan vf = &bp->pf.vf[vf_id]; 97c0c050c5SMichael Chan if (vf->flags & BNXT_VF_SPOOFCHK) 98c0c050c5SMichael Chan old_setting = true; 99c0c050c5SMichael Chan if (old_setting == setting) 100c0c050c5SMichael Chan return 0; 101c0c050c5SMichael Chan 102c0c050c5SMichael Chan func_flags = vf->func_flags; 103c0c050c5SMichael Chan if (setting) 1048eb992e8SMichael Chan func_flags |= FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_ENABLE; 105c0c050c5SMichael Chan else 1068eb992e8SMichael Chan func_flags |= FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_DISABLE; 107c0c050c5SMichael Chan /*TODO: if the driver supports VLAN filter on guest VLAN, 108c0c050c5SMichael Chan * the spoof check should also include vlan anti-spoofing 109c0c050c5SMichael Chan */ 110c0c050c5SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1); 111c193554eSMichael Chan req.fid = cpu_to_le16(vf->fw_fid); 112c0c050c5SMichael Chan req.flags = cpu_to_le32(func_flags); 113c0c050c5SMichael Chan rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 114c0c050c5SMichael Chan if (!rc) { 115c0c050c5SMichael Chan vf->func_flags = func_flags; 116c0c050c5SMichael Chan if (setting) 117c0c050c5SMichael Chan vf->flags |= BNXT_VF_SPOOFCHK; 118c0c050c5SMichael Chan else 119c0c050c5SMichael Chan vf->flags &= ~BNXT_VF_SPOOFCHK; 120c0c050c5SMichael Chan } 121c0c050c5SMichael Chan return rc; 122c0c050c5SMichael Chan } 123c0c050c5SMichael Chan 124c0c050c5SMichael Chan int bnxt_get_vf_config(struct net_device *dev, int vf_id, 125c0c050c5SMichael Chan struct ifla_vf_info *ivi) 126c0c050c5SMichael Chan { 127c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 128c0c050c5SMichael Chan struct bnxt_vf_info *vf; 129c0c050c5SMichael Chan int rc; 130c0c050c5SMichael Chan 131c0c050c5SMichael Chan rc = bnxt_vf_ndo_prep(bp, vf_id); 132c0c050c5SMichael Chan if (rc) 133c0c050c5SMichael Chan return rc; 134c0c050c5SMichael Chan 135c0c050c5SMichael Chan ivi->vf = vf_id; 136c0c050c5SMichael Chan vf = &bp->pf.vf[vf_id]; 137c0c050c5SMichael Chan 138c0c050c5SMichael Chan memcpy(&ivi->mac, vf->mac_addr, ETH_ALEN); 139c0c050c5SMichael Chan ivi->max_tx_rate = vf->max_tx_rate; 140c0c050c5SMichael Chan ivi->min_tx_rate = vf->min_tx_rate; 141c0c050c5SMichael Chan ivi->vlan = vf->vlan; 142f0249056SMichael Chan if (vf->flags & BNXT_VF_QOS) 143f0249056SMichael Chan ivi->qos = vf->vlan >> VLAN_PRIO_SHIFT; 144f0249056SMichael Chan else 145f0249056SMichael Chan ivi->qos = 0; 146f0249056SMichael Chan ivi->spoofchk = !!(vf->flags & BNXT_VF_SPOOFCHK); 147c0c050c5SMichael Chan if (!(vf->flags & BNXT_VF_LINK_FORCED)) 148c0c050c5SMichael Chan ivi->linkstate = IFLA_VF_LINK_STATE_AUTO; 149c0c050c5SMichael Chan else if (vf->flags & BNXT_VF_LINK_UP) 150c0c050c5SMichael Chan ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE; 151c0c050c5SMichael Chan else 152c0c050c5SMichael Chan ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE; 153c0c050c5SMichael Chan 154c0c050c5SMichael Chan return 0; 155c0c050c5SMichael Chan } 156c0c050c5SMichael Chan 157c0c050c5SMichael Chan int bnxt_set_vf_mac(struct net_device *dev, int vf_id, u8 *mac) 158c0c050c5SMichael Chan { 159c0c050c5SMichael Chan struct hwrm_func_cfg_input req = {0}; 160c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 161c0c050c5SMichael Chan struct bnxt_vf_info *vf; 162c0c050c5SMichael Chan int rc; 163c0c050c5SMichael Chan 164c0c050c5SMichael Chan rc = bnxt_vf_ndo_prep(bp, vf_id); 165c0c050c5SMichael Chan if (rc) 166c0c050c5SMichael Chan return rc; 167c0c050c5SMichael Chan /* reject bc or mc mac addr, zero mac addr means allow 168c0c050c5SMichael Chan * VF to use its own mac addr 169c0c050c5SMichael Chan */ 170c0c050c5SMichael Chan if (is_multicast_ether_addr(mac)) { 171c0c050c5SMichael Chan netdev_err(dev, "Invalid VF ethernet address\n"); 172c0c050c5SMichael Chan return -EINVAL; 173c0c050c5SMichael Chan } 174c0c050c5SMichael Chan vf = &bp->pf.vf[vf_id]; 175c0c050c5SMichael Chan 176c0c050c5SMichael Chan memcpy(vf->mac_addr, mac, ETH_ALEN); 177c0c050c5SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1); 178c193554eSMichael Chan req.fid = cpu_to_le16(vf->fw_fid); 179c0c050c5SMichael Chan req.flags = cpu_to_le32(vf->func_flags); 180c0c050c5SMichael Chan req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_MAC_ADDR); 181c0c050c5SMichael Chan memcpy(req.dflt_mac_addr, mac, ETH_ALEN); 182c0c050c5SMichael Chan return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 183c0c050c5SMichael Chan } 184c0c050c5SMichael Chan 18579aab093SMoshe Shemesh int bnxt_set_vf_vlan(struct net_device *dev, int vf_id, u16 vlan_id, u8 qos, 18679aab093SMoshe Shemesh __be16 vlan_proto) 187c0c050c5SMichael Chan { 188c0c050c5SMichael Chan struct hwrm_func_cfg_input req = {0}; 189c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 190c0c050c5SMichael Chan struct bnxt_vf_info *vf; 191c0c050c5SMichael Chan u16 vlan_tag; 192c0c050c5SMichael Chan int rc; 193c0c050c5SMichael Chan 194cf6645f8SMichael Chan if (bp->hwrm_spec_code < 0x10201) 195cf6645f8SMichael Chan return -ENOTSUPP; 196cf6645f8SMichael Chan 19779aab093SMoshe Shemesh if (vlan_proto != htons(ETH_P_8021Q)) 19879aab093SMoshe Shemesh return -EPROTONOSUPPORT; 19979aab093SMoshe Shemesh 200c0c050c5SMichael Chan rc = bnxt_vf_ndo_prep(bp, vf_id); 201c0c050c5SMichael Chan if (rc) 202c0c050c5SMichael Chan return rc; 203c0c050c5SMichael Chan 204c0c050c5SMichael Chan /* TODO: needed to implement proper handling of user priority, 205c0c050c5SMichael Chan * currently fail the command if there is valid priority 206c0c050c5SMichael Chan */ 207c0c050c5SMichael Chan if (vlan_id > 4095 || qos) 208c0c050c5SMichael Chan return -EINVAL; 209c0c050c5SMichael Chan 210c0c050c5SMichael Chan vf = &bp->pf.vf[vf_id]; 211c0c050c5SMichael Chan vlan_tag = vlan_id; 212c0c050c5SMichael Chan if (vlan_tag == vf->vlan) 213c0c050c5SMichael Chan return 0; 214c0c050c5SMichael Chan 215c0c050c5SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1); 216c193554eSMichael Chan req.fid = cpu_to_le16(vf->fw_fid); 217c0c050c5SMichael Chan req.flags = cpu_to_le32(vf->func_flags); 218c0c050c5SMichael Chan req.dflt_vlan = cpu_to_le16(vlan_tag); 219c0c050c5SMichael Chan req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_VLAN); 220c0c050c5SMichael Chan rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 221c0c050c5SMichael Chan if (!rc) 222c0c050c5SMichael Chan vf->vlan = vlan_tag; 223c0c050c5SMichael Chan return rc; 224c0c050c5SMichael Chan } 225c0c050c5SMichael Chan 226c0c050c5SMichael Chan int bnxt_set_vf_bw(struct net_device *dev, int vf_id, int min_tx_rate, 227c0c050c5SMichael Chan int max_tx_rate) 228c0c050c5SMichael Chan { 229c0c050c5SMichael Chan struct hwrm_func_cfg_input req = {0}; 230c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 231c0c050c5SMichael Chan struct bnxt_vf_info *vf; 232c0c050c5SMichael Chan u32 pf_link_speed; 233c0c050c5SMichael Chan int rc; 234c0c050c5SMichael Chan 235c0c050c5SMichael Chan rc = bnxt_vf_ndo_prep(bp, vf_id); 236c0c050c5SMichael Chan if (rc) 237c0c050c5SMichael Chan return rc; 238c0c050c5SMichael Chan 239c0c050c5SMichael Chan vf = &bp->pf.vf[vf_id]; 240c0c050c5SMichael Chan pf_link_speed = bnxt_fw_to_ethtool_speed(bp->link_info.link_speed); 241c0c050c5SMichael Chan if (max_tx_rate > pf_link_speed) { 242c0c050c5SMichael Chan netdev_info(bp->dev, "max tx rate %d exceed PF link speed for VF %d\n", 243c0c050c5SMichael Chan max_tx_rate, vf_id); 244c0c050c5SMichael Chan return -EINVAL; 245c0c050c5SMichael Chan } 246c0c050c5SMichael Chan 247c0c050c5SMichael Chan if (min_tx_rate > pf_link_speed || min_tx_rate > max_tx_rate) { 248c0c050c5SMichael Chan netdev_info(bp->dev, "min tx rate %d is invalid for VF %d\n", 249c0c050c5SMichael Chan min_tx_rate, vf_id); 250c0c050c5SMichael Chan return -EINVAL; 251c0c050c5SMichael Chan } 252c0c050c5SMichael Chan if (min_tx_rate == vf->min_tx_rate && max_tx_rate == vf->max_tx_rate) 253c0c050c5SMichael Chan return 0; 254c0c050c5SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1); 255c193554eSMichael Chan req.fid = cpu_to_le16(vf->fw_fid); 256c0c050c5SMichael Chan req.flags = cpu_to_le32(vf->func_flags); 257c0c050c5SMichael Chan req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_MAX_BW); 258c0c050c5SMichael Chan req.max_bw = cpu_to_le32(max_tx_rate); 259c0c050c5SMichael Chan req.enables |= cpu_to_le32(FUNC_CFG_REQ_ENABLES_MIN_BW); 260c0c050c5SMichael Chan req.min_bw = cpu_to_le32(min_tx_rate); 261c0c050c5SMichael Chan rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 262c0c050c5SMichael Chan if (!rc) { 263c0c050c5SMichael Chan vf->min_tx_rate = min_tx_rate; 264c0c050c5SMichael Chan vf->max_tx_rate = max_tx_rate; 265c0c050c5SMichael Chan } 266c0c050c5SMichael Chan return rc; 267c0c050c5SMichael Chan } 268c0c050c5SMichael Chan 269c0c050c5SMichael Chan int bnxt_set_vf_link_state(struct net_device *dev, int vf_id, int link) 270c0c050c5SMichael Chan { 271c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 272c0c050c5SMichael Chan struct bnxt_vf_info *vf; 273c0c050c5SMichael Chan int rc; 274c0c050c5SMichael Chan 275c0c050c5SMichael Chan rc = bnxt_vf_ndo_prep(bp, vf_id); 276c0c050c5SMichael Chan if (rc) 277c0c050c5SMichael Chan return rc; 278c0c050c5SMichael Chan 279c0c050c5SMichael Chan vf = &bp->pf.vf[vf_id]; 280c0c050c5SMichael Chan 281c0c050c5SMichael Chan vf->flags &= ~(BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED); 282c0c050c5SMichael Chan switch (link) { 283c0c050c5SMichael Chan case IFLA_VF_LINK_STATE_AUTO: 284c0c050c5SMichael Chan vf->flags |= BNXT_VF_LINK_UP; 285c0c050c5SMichael Chan break; 286c0c050c5SMichael Chan case IFLA_VF_LINK_STATE_DISABLE: 287c0c050c5SMichael Chan vf->flags |= BNXT_VF_LINK_FORCED; 288c0c050c5SMichael Chan break; 289c0c050c5SMichael Chan case IFLA_VF_LINK_STATE_ENABLE: 290c0c050c5SMichael Chan vf->flags |= BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED; 291c0c050c5SMichael Chan break; 292c0c050c5SMichael Chan default: 293c0c050c5SMichael Chan netdev_err(bp->dev, "Invalid link option\n"); 294c0c050c5SMichael Chan rc = -EINVAL; 295c0c050c5SMichael Chan break; 296c0c050c5SMichael Chan } 297350a7149SEddie Wai if (vf->flags & (BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED)) 298350a7149SEddie Wai rc = bnxt_hwrm_fwd_async_event_cmpl(bp, vf, 29987c374deSMichael Chan ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE); 300c0c050c5SMichael Chan return rc; 301c0c050c5SMichael Chan } 302c0c050c5SMichael Chan 303c0c050c5SMichael Chan static int bnxt_set_vf_attr(struct bnxt *bp, int num_vfs) 304c0c050c5SMichael Chan { 305c0c050c5SMichael Chan int i; 306c0c050c5SMichael Chan struct bnxt_vf_info *vf; 307c0c050c5SMichael Chan 308c0c050c5SMichael Chan for (i = 0; i < num_vfs; i++) { 309c0c050c5SMichael Chan vf = &bp->pf.vf[i]; 310c0c050c5SMichael Chan memset(vf, 0, sizeof(*vf)); 311c0c050c5SMichael Chan } 312c0c050c5SMichael Chan return 0; 313c0c050c5SMichael Chan } 314c0c050c5SMichael Chan 3154bb6cdceSJeffrey Huang static int bnxt_hwrm_func_vf_resource_free(struct bnxt *bp, int num_vfs) 316c0c050c5SMichael Chan { 317c0c050c5SMichael Chan int i, rc = 0; 318c0c050c5SMichael Chan struct bnxt_pf_info *pf = &bp->pf; 319c0c050c5SMichael Chan struct hwrm_func_vf_resc_free_input req = {0}; 320c0c050c5SMichael Chan 321c0c050c5SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_RESC_FREE, -1, -1); 322c0c050c5SMichael Chan 323c0c050c5SMichael Chan mutex_lock(&bp->hwrm_cmd_lock); 3244bb6cdceSJeffrey Huang for (i = pf->first_vf_id; i < pf->first_vf_id + num_vfs; i++) { 325c0c050c5SMichael Chan req.vf_id = cpu_to_le16(i); 326c0c050c5SMichael Chan rc = _hwrm_send_message(bp, &req, sizeof(req), 327c0c050c5SMichael Chan HWRM_CMD_TIMEOUT); 328c0c050c5SMichael Chan if (rc) 329c0c050c5SMichael Chan break; 330c0c050c5SMichael Chan } 331c0c050c5SMichael Chan mutex_unlock(&bp->hwrm_cmd_lock); 332c0c050c5SMichael Chan return rc; 333c0c050c5SMichael Chan } 334c0c050c5SMichael Chan 335c0c050c5SMichael Chan static void bnxt_free_vf_resources(struct bnxt *bp) 336c0c050c5SMichael Chan { 337c0c050c5SMichael Chan struct pci_dev *pdev = bp->pdev; 338c0c050c5SMichael Chan int i; 339c0c050c5SMichael Chan 340c0c050c5SMichael Chan kfree(bp->pf.vf_event_bmap); 341c0c050c5SMichael Chan bp->pf.vf_event_bmap = NULL; 342c0c050c5SMichael Chan 343c0c050c5SMichael Chan for (i = 0; i < 4; i++) { 344c0c050c5SMichael Chan if (bp->pf.hwrm_cmd_req_addr[i]) { 345c0c050c5SMichael Chan dma_free_coherent(&pdev->dev, BNXT_PAGE_SIZE, 346c0c050c5SMichael Chan bp->pf.hwrm_cmd_req_addr[i], 347c0c050c5SMichael Chan bp->pf.hwrm_cmd_req_dma_addr[i]); 348c0c050c5SMichael Chan bp->pf.hwrm_cmd_req_addr[i] = NULL; 349c0c050c5SMichael Chan } 350c0c050c5SMichael Chan } 351c0c050c5SMichael Chan 352c0c050c5SMichael Chan kfree(bp->pf.vf); 353c0c050c5SMichael Chan bp->pf.vf = NULL; 354c0c050c5SMichael Chan } 355c0c050c5SMichael Chan 356c0c050c5SMichael Chan static int bnxt_alloc_vf_resources(struct bnxt *bp, int num_vfs) 357c0c050c5SMichael Chan { 358c0c050c5SMichael Chan struct pci_dev *pdev = bp->pdev; 359c0c050c5SMichael Chan u32 nr_pages, size, i, j, k = 0; 360c0c050c5SMichael Chan 361c0c050c5SMichael Chan bp->pf.vf = kcalloc(num_vfs, sizeof(struct bnxt_vf_info), GFP_KERNEL); 362c0c050c5SMichael Chan if (!bp->pf.vf) 363c0c050c5SMichael Chan return -ENOMEM; 364c0c050c5SMichael Chan 365c0c050c5SMichael Chan bnxt_set_vf_attr(bp, num_vfs); 366c0c050c5SMichael Chan 367c0c050c5SMichael Chan size = num_vfs * BNXT_HWRM_REQ_MAX_SIZE; 368c0c050c5SMichael Chan nr_pages = size / BNXT_PAGE_SIZE; 369c0c050c5SMichael Chan if (size & (BNXT_PAGE_SIZE - 1)) 370c0c050c5SMichael Chan nr_pages++; 371c0c050c5SMichael Chan 372c0c050c5SMichael Chan for (i = 0; i < nr_pages; i++) { 373c0c050c5SMichael Chan bp->pf.hwrm_cmd_req_addr[i] = 374c0c050c5SMichael Chan dma_alloc_coherent(&pdev->dev, BNXT_PAGE_SIZE, 375c0c050c5SMichael Chan &bp->pf.hwrm_cmd_req_dma_addr[i], 376c0c050c5SMichael Chan GFP_KERNEL); 377c0c050c5SMichael Chan 378c0c050c5SMichael Chan if (!bp->pf.hwrm_cmd_req_addr[i]) 379c0c050c5SMichael Chan return -ENOMEM; 380c0c050c5SMichael Chan 381c0c050c5SMichael Chan for (j = 0; j < BNXT_HWRM_REQS_PER_PAGE && k < num_vfs; j++) { 382c0c050c5SMichael Chan struct bnxt_vf_info *vf = &bp->pf.vf[k]; 383c0c050c5SMichael Chan 384c0c050c5SMichael Chan vf->hwrm_cmd_req_addr = bp->pf.hwrm_cmd_req_addr[i] + 385c0c050c5SMichael Chan j * BNXT_HWRM_REQ_MAX_SIZE; 386c0c050c5SMichael Chan vf->hwrm_cmd_req_dma_addr = 387c0c050c5SMichael Chan bp->pf.hwrm_cmd_req_dma_addr[i] + j * 388c0c050c5SMichael Chan BNXT_HWRM_REQ_MAX_SIZE; 389c0c050c5SMichael Chan k++; 390c0c050c5SMichael Chan } 391c0c050c5SMichael Chan } 392c0c050c5SMichael Chan 393c0c050c5SMichael Chan /* Max 128 VF's */ 394c0c050c5SMichael Chan bp->pf.vf_event_bmap = kzalloc(16, GFP_KERNEL); 395c0c050c5SMichael Chan if (!bp->pf.vf_event_bmap) 396c0c050c5SMichael Chan return -ENOMEM; 397c0c050c5SMichael Chan 398c0c050c5SMichael Chan bp->pf.hwrm_cmd_req_pages = nr_pages; 399c0c050c5SMichael Chan return 0; 400c0c050c5SMichael Chan } 401c0c050c5SMichael Chan 402c0c050c5SMichael Chan static int bnxt_hwrm_func_buf_rgtr(struct bnxt *bp) 403c0c050c5SMichael Chan { 404c0c050c5SMichael Chan struct hwrm_func_buf_rgtr_input req = {0}; 405c0c050c5SMichael Chan 406c0c050c5SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_BUF_RGTR, -1, -1); 407c0c050c5SMichael Chan 408c0c050c5SMichael Chan req.req_buf_num_pages = cpu_to_le16(bp->pf.hwrm_cmd_req_pages); 409c0c050c5SMichael Chan req.req_buf_page_size = cpu_to_le16(BNXT_PAGE_SHIFT); 410c0c050c5SMichael Chan req.req_buf_len = cpu_to_le16(BNXT_HWRM_REQ_MAX_SIZE); 411c0c050c5SMichael Chan req.req_buf_page_addr0 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[0]); 412c0c050c5SMichael Chan req.req_buf_page_addr1 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[1]); 413c0c050c5SMichael Chan req.req_buf_page_addr2 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[2]); 414c0c050c5SMichael Chan req.req_buf_page_addr3 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[3]); 415c0c050c5SMichael Chan 416c0c050c5SMichael Chan return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 417c0c050c5SMichael Chan } 418c0c050c5SMichael Chan 419*4673d664SMichael Chan /* Only called by PF to reserve resources for VFs, returns actual number of 420*4673d664SMichael Chan * VFs configured, or < 0 on error. 421*4673d664SMichael Chan */ 422*4673d664SMichael Chan static int bnxt_hwrm_func_vf_resc_cfg(struct bnxt *bp, int num_vfs) 423*4673d664SMichael Chan { 424*4673d664SMichael Chan struct hwrm_func_vf_resource_cfg_input req = {0}; 425*4673d664SMichael Chan struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 426*4673d664SMichael Chan u16 vf_tx_rings, vf_rx_rings, vf_cp_rings; 427*4673d664SMichael Chan u16 vf_stat_ctx, vf_vnics, vf_ring_grps; 428*4673d664SMichael Chan struct bnxt_pf_info *pf = &bp->pf; 429*4673d664SMichael Chan int i, rc = 0; 430*4673d664SMichael Chan 431*4673d664SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_RESOURCE_CFG, -1, -1); 432*4673d664SMichael Chan 433*4673d664SMichael Chan vf_cp_rings = hw_resc->max_cp_rings - bp->cp_nr_rings; 434*4673d664SMichael Chan vf_stat_ctx = hw_resc->max_stat_ctxs - bp->num_stat_ctxs; 435*4673d664SMichael Chan if (bp->flags & BNXT_FLAG_AGG_RINGS) 436*4673d664SMichael Chan vf_rx_rings = hw_resc->max_rx_rings - bp->rx_nr_rings * 2; 437*4673d664SMichael Chan else 438*4673d664SMichael Chan vf_rx_rings = hw_resc->max_rx_rings - bp->rx_nr_rings; 439*4673d664SMichael Chan vf_ring_grps = hw_resc->max_hw_ring_grps - bp->rx_nr_rings; 440*4673d664SMichael Chan vf_tx_rings = hw_resc->max_tx_rings - bp->tx_nr_rings; 441*4673d664SMichael Chan vf_vnics = hw_resc->max_vnics - bp->nr_vnics; 442*4673d664SMichael Chan vf_vnics = min_t(u16, vf_vnics, vf_rx_rings); 443*4673d664SMichael Chan 444*4673d664SMichael Chan req.min_rsscos_ctx = cpu_to_le16(1); 445*4673d664SMichael Chan req.max_rsscos_ctx = cpu_to_le16(1); 446*4673d664SMichael Chan if (pf->vf_resv_strategy == BNXT_VF_RESV_STRATEGY_MINIMAL) { 447*4673d664SMichael Chan req.min_cmpl_rings = cpu_to_le16(1); 448*4673d664SMichael Chan req.min_tx_rings = cpu_to_le16(1); 449*4673d664SMichael Chan req.min_rx_rings = cpu_to_le16(1); 450*4673d664SMichael Chan req.min_l2_ctxs = cpu_to_le16(1); 451*4673d664SMichael Chan req.min_vnics = cpu_to_le16(1); 452*4673d664SMichael Chan req.min_stat_ctx = cpu_to_le16(1); 453*4673d664SMichael Chan req.min_hw_ring_grps = cpu_to_le16(1); 454*4673d664SMichael Chan } else { 455*4673d664SMichael Chan vf_cp_rings /= num_vfs; 456*4673d664SMichael Chan vf_tx_rings /= num_vfs; 457*4673d664SMichael Chan vf_rx_rings /= num_vfs; 458*4673d664SMichael Chan vf_vnics /= num_vfs; 459*4673d664SMichael Chan vf_stat_ctx /= num_vfs; 460*4673d664SMichael Chan vf_ring_grps /= num_vfs; 461*4673d664SMichael Chan 462*4673d664SMichael Chan req.min_cmpl_rings = cpu_to_le16(vf_cp_rings); 463*4673d664SMichael Chan req.min_tx_rings = cpu_to_le16(vf_tx_rings); 464*4673d664SMichael Chan req.min_rx_rings = cpu_to_le16(vf_rx_rings); 465*4673d664SMichael Chan req.min_l2_ctxs = cpu_to_le16(4); 466*4673d664SMichael Chan req.min_vnics = cpu_to_le16(vf_vnics); 467*4673d664SMichael Chan req.min_stat_ctx = cpu_to_le16(vf_stat_ctx); 468*4673d664SMichael Chan req.min_hw_ring_grps = cpu_to_le16(vf_ring_grps); 469*4673d664SMichael Chan } 470*4673d664SMichael Chan req.max_cmpl_rings = cpu_to_le16(vf_cp_rings); 471*4673d664SMichael Chan req.max_tx_rings = cpu_to_le16(vf_tx_rings); 472*4673d664SMichael Chan req.max_rx_rings = cpu_to_le16(vf_rx_rings); 473*4673d664SMichael Chan req.max_l2_ctxs = cpu_to_le16(4); 474*4673d664SMichael Chan req.max_vnics = cpu_to_le16(vf_vnics); 475*4673d664SMichael Chan req.max_stat_ctx = cpu_to_le16(vf_stat_ctx); 476*4673d664SMichael Chan req.max_hw_ring_grps = cpu_to_le16(vf_ring_grps); 477*4673d664SMichael Chan 478*4673d664SMichael Chan mutex_lock(&bp->hwrm_cmd_lock); 479*4673d664SMichael Chan for (i = 0; i < num_vfs; i++) { 480*4673d664SMichael Chan req.vf_id = cpu_to_le16(pf->first_vf_id + i); 481*4673d664SMichael Chan rc = _hwrm_send_message(bp, &req, sizeof(req), 482*4673d664SMichael Chan HWRM_CMD_TIMEOUT); 483*4673d664SMichael Chan if (rc) { 484*4673d664SMichael Chan rc = -ENOMEM; 485*4673d664SMichael Chan break; 486*4673d664SMichael Chan } 487*4673d664SMichael Chan pf->active_vfs = i + 1; 488*4673d664SMichael Chan pf->vf[i].fw_fid = pf->first_vf_id + i; 489*4673d664SMichael Chan } 490*4673d664SMichael Chan mutex_unlock(&bp->hwrm_cmd_lock); 491*4673d664SMichael Chan if (pf->active_vfs) { 492*4673d664SMichael Chan u16 n = 1; 493*4673d664SMichael Chan 494*4673d664SMichael Chan if (pf->vf_resv_strategy != BNXT_VF_RESV_STRATEGY_MINIMAL) 495*4673d664SMichael Chan n = pf->active_vfs; 496*4673d664SMichael Chan 497*4673d664SMichael Chan hw_resc->max_tx_rings -= vf_tx_rings * n; 498*4673d664SMichael Chan hw_resc->max_rx_rings -= vf_rx_rings * n; 499*4673d664SMichael Chan hw_resc->max_hw_ring_grps -= vf_ring_grps * n; 500*4673d664SMichael Chan hw_resc->max_cp_rings -= vf_cp_rings * n; 501*4673d664SMichael Chan hw_resc->max_rsscos_ctxs -= pf->active_vfs; 502*4673d664SMichael Chan hw_resc->max_stat_ctxs -= vf_stat_ctx * n; 503*4673d664SMichael Chan hw_resc->max_vnics -= vf_vnics * n; 504*4673d664SMichael Chan 505*4673d664SMichael Chan rc = pf->active_vfs; 506*4673d664SMichael Chan } 507*4673d664SMichael Chan return rc; 508*4673d664SMichael Chan } 509*4673d664SMichael Chan 510*4673d664SMichael Chan /* Only called by PF to reserve resources for VFs, returns actual number of 511*4673d664SMichael Chan * VFs configured, or < 0 on error. 512*4673d664SMichael Chan */ 51392268c32SMichael Chan static int bnxt_hwrm_func_cfg(struct bnxt *bp, int num_vfs) 514c0c050c5SMichael Chan { 515c0c050c5SMichael Chan u32 rc = 0, mtu, i; 516c0c050c5SMichael Chan u16 vf_tx_rings, vf_rx_rings, vf_cp_rings, vf_stat_ctx, vf_vnics; 5176a4f2947SMichael Chan struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 5186a4f2947SMichael Chan u16 vf_ring_grps, max_stat_ctxs; 519c0c050c5SMichael Chan struct hwrm_func_cfg_input req = {0}; 520c0c050c5SMichael Chan struct bnxt_pf_info *pf = &bp->pf; 521391be5c2SMichael Chan int total_vf_tx_rings = 0; 522c0c050c5SMichael Chan 523c0c050c5SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1); 524c0c050c5SMichael Chan 5256a4f2947SMichael Chan max_stat_ctxs = hw_resc->max_stat_ctxs; 5266a4f2947SMichael Chan 527c0c050c5SMichael Chan /* Remaining rings are distributed equally amongs VF's for now */ 5286a4f2947SMichael Chan vf_cp_rings = (hw_resc->max_cp_rings - bp->cp_nr_rings) / num_vfs; 5296a4f2947SMichael Chan vf_stat_ctx = (max_stat_ctxs - bp->num_stat_ctxs) / num_vfs; 530c0c050c5SMichael Chan if (bp->flags & BNXT_FLAG_AGG_RINGS) 5316a4f2947SMichael Chan vf_rx_rings = (hw_resc->max_rx_rings - bp->rx_nr_rings * 2) / 53292268c32SMichael Chan num_vfs; 533c0c050c5SMichael Chan else 5346a4f2947SMichael Chan vf_rx_rings = (hw_resc->max_rx_rings - bp->rx_nr_rings) / 5356a4f2947SMichael Chan num_vfs; 5366a4f2947SMichael Chan vf_ring_grps = (hw_resc->max_hw_ring_grps - bp->rx_nr_rings) / num_vfs; 5376a4f2947SMichael Chan vf_tx_rings = (hw_resc->max_tx_rings - bp->tx_nr_rings) / num_vfs; 5386a4f2947SMichael Chan vf_vnics = (hw_resc->max_vnics - bp->nr_vnics) / num_vfs; 5398427af81SMichael Chan vf_vnics = min_t(u16, vf_vnics, vf_rx_rings); 540c0c050c5SMichael Chan 541c0c050c5SMichael Chan req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_MTU | 542c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_MRU | 543c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS | 544c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS | 545c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS | 546c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS | 547c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS | 548c0c050c5SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_L2_CTXS | 549b72d4a68SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_VNICS | 550b72d4a68SMichael Chan FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS); 551c0c050c5SMichael Chan 552c0c050c5SMichael Chan mtu = bp->dev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; 553c0c050c5SMichael Chan req.mru = cpu_to_le16(mtu); 554c0c050c5SMichael Chan req.mtu = cpu_to_le16(mtu); 555c0c050c5SMichael Chan 556c0c050c5SMichael Chan req.num_rsscos_ctxs = cpu_to_le16(1); 557c0c050c5SMichael Chan req.num_cmpl_rings = cpu_to_le16(vf_cp_rings); 558c0c050c5SMichael Chan req.num_tx_rings = cpu_to_le16(vf_tx_rings); 559c0c050c5SMichael Chan req.num_rx_rings = cpu_to_le16(vf_rx_rings); 560b72d4a68SMichael Chan req.num_hw_ring_grps = cpu_to_le16(vf_ring_grps); 561c0c050c5SMichael Chan req.num_l2_ctxs = cpu_to_le16(4); 562c0c050c5SMichael Chan 563c0c050c5SMichael Chan req.num_vnics = cpu_to_le16(vf_vnics); 564c0c050c5SMichael Chan /* FIXME spec currently uses 1 bit for stats ctx */ 565c0c050c5SMichael Chan req.num_stat_ctxs = cpu_to_le16(vf_stat_ctx); 566c0c050c5SMichael Chan 567c0c050c5SMichael Chan mutex_lock(&bp->hwrm_cmd_lock); 56892268c32SMichael Chan for (i = 0; i < num_vfs; i++) { 569391be5c2SMichael Chan int vf_tx_rsvd = vf_tx_rings; 570391be5c2SMichael Chan 571c193554eSMichael Chan req.fid = cpu_to_le16(pf->first_vf_id + i); 572c0c050c5SMichael Chan rc = _hwrm_send_message(bp, &req, sizeof(req), 573c0c050c5SMichael Chan HWRM_CMD_TIMEOUT); 574c0c050c5SMichael Chan if (rc) 575c0c050c5SMichael Chan break; 57692268c32SMichael Chan pf->active_vfs = i + 1; 577c193554eSMichael Chan pf->vf[i].fw_fid = le16_to_cpu(req.fid); 578391be5c2SMichael Chan rc = __bnxt_hwrm_get_tx_rings(bp, pf->vf[i].fw_fid, 579391be5c2SMichael Chan &vf_tx_rsvd); 580391be5c2SMichael Chan if (rc) 581391be5c2SMichael Chan break; 582391be5c2SMichael Chan total_vf_tx_rings += vf_tx_rsvd; 583c0c050c5SMichael Chan } 584c0c050c5SMichael Chan mutex_unlock(&bp->hwrm_cmd_lock); 585*4673d664SMichael Chan if (rc) 586*4673d664SMichael Chan rc = -ENOMEM; 587*4673d664SMichael Chan if (pf->active_vfs) { 5886a4f2947SMichael Chan hw_resc->max_tx_rings -= total_vf_tx_rings; 5896a4f2947SMichael Chan hw_resc->max_rx_rings -= vf_rx_rings * num_vfs; 5906a4f2947SMichael Chan hw_resc->max_hw_ring_grps -= vf_ring_grps * num_vfs; 5916a4f2947SMichael Chan hw_resc->max_cp_rings -= vf_cp_rings * num_vfs; 5926a4f2947SMichael Chan hw_resc->max_rsscos_ctxs -= num_vfs; 5936a4f2947SMichael Chan hw_resc->max_stat_ctxs -= vf_stat_ctx * num_vfs; 5946a4f2947SMichael Chan hw_resc->max_vnics -= vf_vnics * num_vfs; 595*4673d664SMichael Chan rc = pf->active_vfs; 596c0c050c5SMichael Chan } 597c0c050c5SMichael Chan return rc; 598c0c050c5SMichael Chan } 599c0c050c5SMichael Chan 600*4673d664SMichael Chan static int bnxt_func_cfg(struct bnxt *bp, int num_vfs) 601*4673d664SMichael Chan { 602*4673d664SMichael Chan if (bp->flags & BNXT_FLAG_NEW_RM) 603*4673d664SMichael Chan return bnxt_hwrm_func_vf_resc_cfg(bp, num_vfs); 604*4673d664SMichael Chan else 605*4673d664SMichael Chan return bnxt_hwrm_func_cfg(bp, num_vfs); 606*4673d664SMichael Chan } 607*4673d664SMichael Chan 608c0c050c5SMichael Chan static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs) 609c0c050c5SMichael Chan { 610c0c050c5SMichael Chan int rc = 0, vfs_supported; 611c0c050c5SMichael Chan int min_rx_rings, min_tx_rings, min_rss_ctxs; 6126a4f2947SMichael Chan struct bnxt_hw_resc *hw_resc = &bp->hw_resc; 613c0c050c5SMichael Chan int tx_ok = 0, rx_ok = 0, rss_ok = 0; 61402157079SMichael Chan int avail_cp, avail_stat; 615c0c050c5SMichael Chan 616c0c050c5SMichael Chan /* Check if we can enable requested num of vf's. At a mininum 617c0c050c5SMichael Chan * we require 1 RX 1 TX rings for each VF. In this minimum conf 618c0c050c5SMichael Chan * features like TPA will not be available. 619c0c050c5SMichael Chan */ 620c0c050c5SMichael Chan vfs_supported = *num_vfs; 621c0c050c5SMichael Chan 6226a4f2947SMichael Chan avail_cp = hw_resc->max_cp_rings - bp->cp_nr_rings; 6236a4f2947SMichael Chan avail_stat = hw_resc->max_stat_ctxs - bp->num_stat_ctxs; 62402157079SMichael Chan avail_cp = min_t(int, avail_cp, avail_stat); 62502157079SMichael Chan 626c0c050c5SMichael Chan while (vfs_supported) { 627c0c050c5SMichael Chan min_rx_rings = vfs_supported; 628c0c050c5SMichael Chan min_tx_rings = vfs_supported; 629c0c050c5SMichael Chan min_rss_ctxs = vfs_supported; 630c0c050c5SMichael Chan 631c0c050c5SMichael Chan if (bp->flags & BNXT_FLAG_AGG_RINGS) { 6326a4f2947SMichael Chan if (hw_resc->max_rx_rings - bp->rx_nr_rings * 2 >= 633c0c050c5SMichael Chan min_rx_rings) 634c0c050c5SMichael Chan rx_ok = 1; 635c0c050c5SMichael Chan } else { 6366a4f2947SMichael Chan if (hw_resc->max_rx_rings - bp->rx_nr_rings >= 637c0c050c5SMichael Chan min_rx_rings) 638c0c050c5SMichael Chan rx_ok = 1; 639c0c050c5SMichael Chan } 6406a4f2947SMichael Chan if (hw_resc->max_vnics - bp->nr_vnics < min_rx_rings || 64102157079SMichael Chan avail_cp < min_rx_rings) 6428427af81SMichael Chan rx_ok = 0; 643c0c050c5SMichael Chan 6446a4f2947SMichael Chan if (hw_resc->max_tx_rings - bp->tx_nr_rings >= min_tx_rings && 64502157079SMichael Chan avail_cp >= min_tx_rings) 646c0c050c5SMichael Chan tx_ok = 1; 647c0c050c5SMichael Chan 6486a4f2947SMichael Chan if (hw_resc->max_rsscos_ctxs - bp->rsscos_nr_ctxs >= 6496a4f2947SMichael Chan min_rss_ctxs) 650c0c050c5SMichael Chan rss_ok = 1; 651c0c050c5SMichael Chan 652c0c050c5SMichael Chan if (tx_ok && rx_ok && rss_ok) 653c0c050c5SMichael Chan break; 654c0c050c5SMichael Chan 655c0c050c5SMichael Chan vfs_supported--; 656c0c050c5SMichael Chan } 657c0c050c5SMichael Chan 658c0c050c5SMichael Chan if (!vfs_supported) { 659c0c050c5SMichael Chan netdev_err(bp->dev, "Cannot enable VF's as all resources are used by PF\n"); 660c0c050c5SMichael Chan return -EINVAL; 661c0c050c5SMichael Chan } 662c0c050c5SMichael Chan 663c0c050c5SMichael Chan if (vfs_supported != *num_vfs) { 664c0c050c5SMichael Chan netdev_info(bp->dev, "Requested VFs %d, can enable %d\n", 665c0c050c5SMichael Chan *num_vfs, vfs_supported); 666c0c050c5SMichael Chan *num_vfs = vfs_supported; 667c0c050c5SMichael Chan } 668c0c050c5SMichael Chan 669c0c050c5SMichael Chan rc = bnxt_alloc_vf_resources(bp, *num_vfs); 670c0c050c5SMichael Chan if (rc) 671c0c050c5SMichael Chan goto err_out1; 672c0c050c5SMichael Chan 673c0c050c5SMichael Chan /* Reserve resources for VFs */ 674*4673d664SMichael Chan rc = bnxt_func_cfg(bp, *num_vfs); 675*4673d664SMichael Chan if (rc != *num_vfs) { 676*4673d664SMichael Chan if (rc <= 0) { 677*4673d664SMichael Chan netdev_warn(bp->dev, "Unable to reserve resources for SRIOV.\n"); 678*4673d664SMichael Chan *num_vfs = 0; 679c0c050c5SMichael Chan goto err_out2; 680*4673d664SMichael Chan } 681*4673d664SMichael Chan netdev_warn(bp->dev, "Only able to reserve resources for %d VFs.\n", rc); 682*4673d664SMichael Chan *num_vfs = rc; 683*4673d664SMichael Chan } 684c0c050c5SMichael Chan 685c0c050c5SMichael Chan /* Register buffers for VFs */ 686c0c050c5SMichael Chan rc = bnxt_hwrm_func_buf_rgtr(bp); 687c0c050c5SMichael Chan if (rc) 688c0c050c5SMichael Chan goto err_out2; 689c0c050c5SMichael Chan 6902f593846SMichael Chan bnxt_ulp_sriov_cfg(bp, *num_vfs); 6912f593846SMichael Chan 692c0c050c5SMichael Chan rc = pci_enable_sriov(bp->pdev, *num_vfs); 693c0c050c5SMichael Chan if (rc) 694c0c050c5SMichael Chan goto err_out2; 695c0c050c5SMichael Chan 696c0c050c5SMichael Chan return 0; 697c0c050c5SMichael Chan 698c0c050c5SMichael Chan err_out2: 699c0c050c5SMichael Chan /* Free the resources reserved for various VF's */ 7004bb6cdceSJeffrey Huang bnxt_hwrm_func_vf_resource_free(bp, *num_vfs); 701c0c050c5SMichael Chan 702c0c050c5SMichael Chan err_out1: 703c0c050c5SMichael Chan bnxt_free_vf_resources(bp); 704c0c050c5SMichael Chan 705c0c050c5SMichael Chan return rc; 706c0c050c5SMichael Chan } 707c0c050c5SMichael Chan 708c0c050c5SMichael Chan void bnxt_sriov_disable(struct bnxt *bp) 709c0c050c5SMichael Chan { 7104bb6cdceSJeffrey Huang u16 num_vfs = pci_num_vf(bp->pdev); 7114bb6cdceSJeffrey Huang 7124bb6cdceSJeffrey Huang if (!num_vfs) 713c0c050c5SMichael Chan return; 714c0c050c5SMichael Chan 7154ab0c6a8SSathya Perla /* synchronize VF and VF-rep create and destroy */ 7164ab0c6a8SSathya Perla mutex_lock(&bp->sriov_lock); 7174ab0c6a8SSathya Perla bnxt_vf_reps_destroy(bp); 7184ab0c6a8SSathya Perla 7194bb6cdceSJeffrey Huang if (pci_vfs_assigned(bp->pdev)) { 72019241368SJeffrey Huang bnxt_hwrm_fwd_async_event_cmpl( 72187c374deSMichael Chan bp, NULL, ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD); 7224bb6cdceSJeffrey Huang netdev_warn(bp->dev, "Unable to free %d VFs because some are assigned to VMs.\n", 7234bb6cdceSJeffrey Huang num_vfs); 7244bb6cdceSJeffrey Huang } else { 725c0c050c5SMichael Chan pci_disable_sriov(bp->pdev); 7264bb6cdceSJeffrey Huang /* Free the HW resources reserved for various VF's */ 7274bb6cdceSJeffrey Huang bnxt_hwrm_func_vf_resource_free(bp, num_vfs); 7284bb6cdceSJeffrey Huang } 7294ab0c6a8SSathya Perla mutex_unlock(&bp->sriov_lock); 730c0c050c5SMichael Chan 731c0c050c5SMichael Chan bnxt_free_vf_resources(bp); 732c0c050c5SMichael Chan 733c0c050c5SMichael Chan bp->pf.active_vfs = 0; 7344a21b49bSMichael Chan /* Reclaim all resources for the PF. */ 7357b08f661SMichael Chan rtnl_lock(); 7367b08f661SMichael Chan bnxt_restore_pf_fw_resources(bp); 7377b08f661SMichael Chan rtnl_unlock(); 7382f593846SMichael Chan 7392f593846SMichael Chan bnxt_ulp_sriov_cfg(bp, 0); 740c0c050c5SMichael Chan } 741c0c050c5SMichael Chan 742c0c050c5SMichael Chan int bnxt_sriov_configure(struct pci_dev *pdev, int num_vfs) 743c0c050c5SMichael Chan { 744c0c050c5SMichael Chan struct net_device *dev = pci_get_drvdata(pdev); 745c0c050c5SMichael Chan struct bnxt *bp = netdev_priv(dev); 746c0c050c5SMichael Chan 747c0c050c5SMichael Chan if (!(bp->flags & BNXT_FLAG_USING_MSIX)) { 748c0c050c5SMichael Chan netdev_warn(dev, "Not allow SRIOV if the irq mode is not MSIX\n"); 749c0c050c5SMichael Chan return 0; 750c0c050c5SMichael Chan } 751c0c050c5SMichael Chan 752c0c050c5SMichael Chan rtnl_lock(); 753c0c050c5SMichael Chan if (!netif_running(dev)) { 754c0c050c5SMichael Chan netdev_warn(dev, "Reject SRIOV config request since if is down!\n"); 755c0c050c5SMichael Chan rtnl_unlock(); 756c0c050c5SMichael Chan return 0; 757c0c050c5SMichael Chan } 758c0c050c5SMichael Chan bp->sriov_cfg = true; 759c0c050c5SMichael Chan rtnl_unlock(); 7604bb6cdceSJeffrey Huang 7614bb6cdceSJeffrey Huang if (pci_vfs_assigned(bp->pdev)) { 7624bb6cdceSJeffrey Huang netdev_warn(dev, "Unable to configure SRIOV since some VFs are assigned to VMs.\n"); 7634bb6cdceSJeffrey Huang num_vfs = 0; 7644bb6cdceSJeffrey Huang goto sriov_cfg_exit; 765c0c050c5SMichael Chan } 766c0c050c5SMichael Chan 767c0c050c5SMichael Chan /* Check if enabled VFs is same as requested */ 7684bb6cdceSJeffrey Huang if (num_vfs && num_vfs == bp->pf.active_vfs) 7694bb6cdceSJeffrey Huang goto sriov_cfg_exit; 7704bb6cdceSJeffrey Huang 7714bb6cdceSJeffrey Huang /* if there are previous existing VFs, clean them up */ 7724bb6cdceSJeffrey Huang bnxt_sriov_disable(bp); 7734bb6cdceSJeffrey Huang if (!num_vfs) 7744bb6cdceSJeffrey Huang goto sriov_cfg_exit; 775c0c050c5SMichael Chan 776c0c050c5SMichael Chan bnxt_sriov_enable(bp, &num_vfs); 777c0c050c5SMichael Chan 7784bb6cdceSJeffrey Huang sriov_cfg_exit: 779c0c050c5SMichael Chan bp->sriov_cfg = false; 780c0c050c5SMichael Chan wake_up(&bp->sriov_cfg_wait); 781c0c050c5SMichael Chan 782c0c050c5SMichael Chan return num_vfs; 783c0c050c5SMichael Chan } 784c0c050c5SMichael Chan 785c0c050c5SMichael Chan static int bnxt_hwrm_fwd_resp(struct bnxt *bp, struct bnxt_vf_info *vf, 786c0c050c5SMichael Chan void *encap_resp, __le64 encap_resp_addr, 787c0c050c5SMichael Chan __le16 encap_resp_cpr, u32 msg_size) 788c0c050c5SMichael Chan { 789c0c050c5SMichael Chan int rc = 0; 790c0c050c5SMichael Chan struct hwrm_fwd_resp_input req = {0}; 791c0c050c5SMichael Chan struct hwrm_fwd_resp_output *resp = bp->hwrm_cmd_resp_addr; 792c0c050c5SMichael Chan 793c0c050c5SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FWD_RESP, -1, -1); 794c0c050c5SMichael Chan 795c0c050c5SMichael Chan /* Set the new target id */ 796c0c050c5SMichael Chan req.target_id = cpu_to_le16(vf->fw_fid); 797c193554eSMichael Chan req.encap_resp_target_id = cpu_to_le16(vf->fw_fid); 798c0c050c5SMichael Chan req.encap_resp_len = cpu_to_le16(msg_size); 799c0c050c5SMichael Chan req.encap_resp_addr = encap_resp_addr; 800c0c050c5SMichael Chan req.encap_resp_cmpl_ring = encap_resp_cpr; 801c0c050c5SMichael Chan memcpy(req.encap_resp, encap_resp, msg_size); 802c0c050c5SMichael Chan 803c0c050c5SMichael Chan mutex_lock(&bp->hwrm_cmd_lock); 804c0c050c5SMichael Chan rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 805c0c050c5SMichael Chan 806c0c050c5SMichael Chan if (rc) { 807c0c050c5SMichael Chan netdev_err(bp->dev, "hwrm_fwd_resp failed. rc:%d\n", rc); 808c0c050c5SMichael Chan goto fwd_resp_exit; 809c0c050c5SMichael Chan } 810c0c050c5SMichael Chan 811c0c050c5SMichael Chan if (resp->error_code) { 812c0c050c5SMichael Chan netdev_err(bp->dev, "hwrm_fwd_resp error %d\n", 813c0c050c5SMichael Chan resp->error_code); 814c0c050c5SMichael Chan rc = -1; 815c0c050c5SMichael Chan } 816c0c050c5SMichael Chan 817c0c050c5SMichael Chan fwd_resp_exit: 818c0c050c5SMichael Chan mutex_unlock(&bp->hwrm_cmd_lock); 819c0c050c5SMichael Chan return rc; 820c0c050c5SMichael Chan } 821c0c050c5SMichael Chan 822c0c050c5SMichael Chan static int bnxt_hwrm_fwd_err_resp(struct bnxt *bp, struct bnxt_vf_info *vf, 823c0c050c5SMichael Chan u32 msg_size) 824c0c050c5SMichael Chan { 825c0c050c5SMichael Chan int rc = 0; 826c0c050c5SMichael Chan struct hwrm_reject_fwd_resp_input req = {0}; 827c0c050c5SMichael Chan struct hwrm_reject_fwd_resp_output *resp = bp->hwrm_cmd_resp_addr; 828c0c050c5SMichael Chan 829c0c050c5SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_REJECT_FWD_RESP, -1, -1); 830c0c050c5SMichael Chan /* Set the new target id */ 831c0c050c5SMichael Chan req.target_id = cpu_to_le16(vf->fw_fid); 832c193554eSMichael Chan req.encap_resp_target_id = cpu_to_le16(vf->fw_fid); 833c0c050c5SMichael Chan memcpy(req.encap_request, vf->hwrm_cmd_req_addr, msg_size); 834c0c050c5SMichael Chan 835c0c050c5SMichael Chan mutex_lock(&bp->hwrm_cmd_lock); 836c0c050c5SMichael Chan rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 837c0c050c5SMichael Chan 838c0c050c5SMichael Chan if (rc) { 839c0c050c5SMichael Chan netdev_err(bp->dev, "hwrm_fwd_err_resp failed. rc:%d\n", rc); 840c0c050c5SMichael Chan goto fwd_err_resp_exit; 841c0c050c5SMichael Chan } 842c0c050c5SMichael Chan 843c0c050c5SMichael Chan if (resp->error_code) { 844c0c050c5SMichael Chan netdev_err(bp->dev, "hwrm_fwd_err_resp error %d\n", 845c0c050c5SMichael Chan resp->error_code); 846c0c050c5SMichael Chan rc = -1; 847c0c050c5SMichael Chan } 848c0c050c5SMichael Chan 849c0c050c5SMichael Chan fwd_err_resp_exit: 850c0c050c5SMichael Chan mutex_unlock(&bp->hwrm_cmd_lock); 851c0c050c5SMichael Chan return rc; 852c0c050c5SMichael Chan } 853c0c050c5SMichael Chan 854c0c050c5SMichael Chan static int bnxt_hwrm_exec_fwd_resp(struct bnxt *bp, struct bnxt_vf_info *vf, 855c0c050c5SMichael Chan u32 msg_size) 856c0c050c5SMichael Chan { 857c0c050c5SMichael Chan int rc = 0; 858c0c050c5SMichael Chan struct hwrm_exec_fwd_resp_input req = {0}; 859c0c050c5SMichael Chan struct hwrm_exec_fwd_resp_output *resp = bp->hwrm_cmd_resp_addr; 860c0c050c5SMichael Chan 861c0c050c5SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_EXEC_FWD_RESP, -1, -1); 862c0c050c5SMichael Chan /* Set the new target id */ 863c0c050c5SMichael Chan req.target_id = cpu_to_le16(vf->fw_fid); 864c193554eSMichael Chan req.encap_resp_target_id = cpu_to_le16(vf->fw_fid); 865c0c050c5SMichael Chan memcpy(req.encap_request, vf->hwrm_cmd_req_addr, msg_size); 866c0c050c5SMichael Chan 867c0c050c5SMichael Chan mutex_lock(&bp->hwrm_cmd_lock); 868c0c050c5SMichael Chan rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 869c0c050c5SMichael Chan 870c0c050c5SMichael Chan if (rc) { 871c0c050c5SMichael Chan netdev_err(bp->dev, "hwrm_exec_fw_resp failed. rc:%d\n", rc); 872c0c050c5SMichael Chan goto exec_fwd_resp_exit; 873c0c050c5SMichael Chan } 874c0c050c5SMichael Chan 875c0c050c5SMichael Chan if (resp->error_code) { 876c0c050c5SMichael Chan netdev_err(bp->dev, "hwrm_exec_fw_resp error %d\n", 877c0c050c5SMichael Chan resp->error_code); 878c0c050c5SMichael Chan rc = -1; 879c0c050c5SMichael Chan } 880c0c050c5SMichael Chan 881c0c050c5SMichael Chan exec_fwd_resp_exit: 882c0c050c5SMichael Chan mutex_unlock(&bp->hwrm_cmd_lock); 883c0c050c5SMichael Chan return rc; 884c0c050c5SMichael Chan } 885c0c050c5SMichael Chan 886c0c050c5SMichael Chan static int bnxt_vf_validate_set_mac(struct bnxt *bp, struct bnxt_vf_info *vf) 887c0c050c5SMichael Chan { 888c0c050c5SMichael Chan u32 msg_size = sizeof(struct hwrm_cfa_l2_filter_alloc_input); 889c0c050c5SMichael Chan struct hwrm_cfa_l2_filter_alloc_input *req = 890c0c050c5SMichael Chan (struct hwrm_cfa_l2_filter_alloc_input *)vf->hwrm_cmd_req_addr; 891c0c050c5SMichael Chan 892c0c050c5SMichael Chan if (!is_valid_ether_addr(vf->mac_addr) || 893c0c050c5SMichael Chan ether_addr_equal((const u8 *)req->l2_addr, vf->mac_addr)) 894c0c050c5SMichael Chan return bnxt_hwrm_exec_fwd_resp(bp, vf, msg_size); 895c0c050c5SMichael Chan else 896c0c050c5SMichael Chan return bnxt_hwrm_fwd_err_resp(bp, vf, msg_size); 897c0c050c5SMichael Chan } 898c0c050c5SMichael Chan 899c0c050c5SMichael Chan static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf) 900c0c050c5SMichael Chan { 901c0c050c5SMichael Chan int rc = 0; 902c0c050c5SMichael Chan 903c0c050c5SMichael Chan if (!(vf->flags & BNXT_VF_LINK_FORCED)) { 904c0c050c5SMichael Chan /* real link */ 905c0c050c5SMichael Chan rc = bnxt_hwrm_exec_fwd_resp( 906c0c050c5SMichael Chan bp, vf, sizeof(struct hwrm_port_phy_qcfg_input)); 907c0c050c5SMichael Chan } else { 908c0c050c5SMichael Chan struct hwrm_port_phy_qcfg_output phy_qcfg_resp; 909c0c050c5SMichael Chan struct hwrm_port_phy_qcfg_input *phy_qcfg_req; 910c0c050c5SMichael Chan 911c0c050c5SMichael Chan phy_qcfg_req = 912c0c050c5SMichael Chan (struct hwrm_port_phy_qcfg_input *)vf->hwrm_cmd_req_addr; 913c0c050c5SMichael Chan mutex_lock(&bp->hwrm_cmd_lock); 914c0c050c5SMichael Chan memcpy(&phy_qcfg_resp, &bp->link_info.phy_qcfg_resp, 915c0c050c5SMichael Chan sizeof(phy_qcfg_resp)); 916c0c050c5SMichael Chan mutex_unlock(&bp->hwrm_cmd_lock); 917c0c050c5SMichael Chan phy_qcfg_resp.seq_id = phy_qcfg_req->seq_id; 918c0c050c5SMichael Chan 919c0c050c5SMichael Chan if (vf->flags & BNXT_VF_LINK_UP) { 920c0c050c5SMichael Chan /* if physical link is down, force link up on VF */ 92173b9bad6SMichael Chan if (phy_qcfg_resp.link != 92273b9bad6SMichael Chan PORT_PHY_QCFG_RESP_LINK_LINK) { 923c0c050c5SMichael Chan phy_qcfg_resp.link = 924c0c050c5SMichael Chan PORT_PHY_QCFG_RESP_LINK_LINK; 92511f15ed3SMichael Chan phy_qcfg_resp.link_speed = cpu_to_le16( 92611f15ed3SMichael Chan PORT_PHY_QCFG_RESP_LINK_SPEED_10GB); 927acb20054SMichael Chan phy_qcfg_resp.duplex_cfg = 928acb20054SMichael Chan PORT_PHY_QCFG_RESP_DUPLEX_CFG_FULL; 929acb20054SMichael Chan phy_qcfg_resp.duplex_state = 930acb20054SMichael Chan PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL; 931c0c050c5SMichael Chan phy_qcfg_resp.pause = 932c0c050c5SMichael Chan (PORT_PHY_QCFG_RESP_PAUSE_TX | 933c0c050c5SMichael Chan PORT_PHY_QCFG_RESP_PAUSE_RX); 934c0c050c5SMichael Chan } 935c0c050c5SMichael Chan } else { 936c0c050c5SMichael Chan /* force link down */ 937c0c050c5SMichael Chan phy_qcfg_resp.link = PORT_PHY_QCFG_RESP_LINK_NO_LINK; 938c0c050c5SMichael Chan phy_qcfg_resp.link_speed = 0; 939acb20054SMichael Chan phy_qcfg_resp.duplex_state = 940acb20054SMichael Chan PORT_PHY_QCFG_RESP_DUPLEX_STATE_HALF; 941c0c050c5SMichael Chan phy_qcfg_resp.pause = 0; 942c0c050c5SMichael Chan } 943c0c050c5SMichael Chan rc = bnxt_hwrm_fwd_resp(bp, vf, &phy_qcfg_resp, 944c0c050c5SMichael Chan phy_qcfg_req->resp_addr, 945c0c050c5SMichael Chan phy_qcfg_req->cmpl_ring, 946c0c050c5SMichael Chan sizeof(phy_qcfg_resp)); 947c0c050c5SMichael Chan } 948c0c050c5SMichael Chan return rc; 949c0c050c5SMichael Chan } 950c0c050c5SMichael Chan 951c0c050c5SMichael Chan static int bnxt_vf_req_validate_snd(struct bnxt *bp, struct bnxt_vf_info *vf) 952c0c050c5SMichael Chan { 953c0c050c5SMichael Chan int rc = 0; 954a8643e16SMichael Chan struct input *encap_req = vf->hwrm_cmd_req_addr; 955a8643e16SMichael Chan u32 req_type = le16_to_cpu(encap_req->req_type); 956c0c050c5SMichael Chan 957c0c050c5SMichael Chan switch (req_type) { 958c0c050c5SMichael Chan case HWRM_CFA_L2_FILTER_ALLOC: 959c0c050c5SMichael Chan rc = bnxt_vf_validate_set_mac(bp, vf); 960c0c050c5SMichael Chan break; 961c0c050c5SMichael Chan case HWRM_FUNC_CFG: 962c0c050c5SMichael Chan /* TODO Validate if VF is allowed to change mac address, 963c0c050c5SMichael Chan * mtu, num of rings etc 964c0c050c5SMichael Chan */ 965c0c050c5SMichael Chan rc = bnxt_hwrm_exec_fwd_resp( 966c0c050c5SMichael Chan bp, vf, sizeof(struct hwrm_func_cfg_input)); 967c0c050c5SMichael Chan break; 968c0c050c5SMichael Chan case HWRM_PORT_PHY_QCFG: 969c0c050c5SMichael Chan rc = bnxt_vf_set_link(bp, vf); 970c0c050c5SMichael Chan break; 971c0c050c5SMichael Chan default: 972c0c050c5SMichael Chan break; 973c0c050c5SMichael Chan } 974c0c050c5SMichael Chan return rc; 975c0c050c5SMichael Chan } 976c0c050c5SMichael Chan 977c0c050c5SMichael Chan void bnxt_hwrm_exec_fwd_req(struct bnxt *bp) 978c0c050c5SMichael Chan { 979c0c050c5SMichael Chan u32 i = 0, active_vfs = bp->pf.active_vfs, vf_id; 980c0c050c5SMichael Chan 981c0c050c5SMichael Chan /* Scan through VF's and process commands */ 982c0c050c5SMichael Chan while (1) { 983c0c050c5SMichael Chan vf_id = find_next_bit(bp->pf.vf_event_bmap, active_vfs, i); 984c0c050c5SMichael Chan if (vf_id >= active_vfs) 985c0c050c5SMichael Chan break; 986c0c050c5SMichael Chan 987c0c050c5SMichael Chan clear_bit(vf_id, bp->pf.vf_event_bmap); 988c0c050c5SMichael Chan bnxt_vf_req_validate_snd(bp, &bp->pf.vf[vf_id]); 989c0c050c5SMichael Chan i = vf_id + 1; 990c0c050c5SMichael Chan } 991c0c050c5SMichael Chan } 992379a80a1SMichael Chan 993379a80a1SMichael Chan void bnxt_update_vf_mac(struct bnxt *bp) 994379a80a1SMichael Chan { 995379a80a1SMichael Chan struct hwrm_func_qcaps_input req = {0}; 996379a80a1SMichael Chan struct hwrm_func_qcaps_output *resp = bp->hwrm_cmd_resp_addr; 997379a80a1SMichael Chan 998379a80a1SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCAPS, -1, -1); 999379a80a1SMichael Chan req.fid = cpu_to_le16(0xffff); 1000379a80a1SMichael Chan 1001379a80a1SMichael Chan mutex_lock(&bp->hwrm_cmd_lock); 1002379a80a1SMichael Chan if (_hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT)) 1003379a80a1SMichael Chan goto update_vf_mac_exit; 1004379a80a1SMichael Chan 10053874d6a8SJeffrey Huang /* Store MAC address from the firmware. There are 2 cases: 10063874d6a8SJeffrey Huang * 1. MAC address is valid. It is assigned from the PF and we 10073874d6a8SJeffrey Huang * need to override the current VF MAC address with it. 10083874d6a8SJeffrey Huang * 2. MAC address is zero. The VF will use a random MAC address by 10093874d6a8SJeffrey Huang * default but the stored zero MAC will allow the VF user to change 10103874d6a8SJeffrey Huang * the random MAC address using ndo_set_mac_address() if he wants. 10113874d6a8SJeffrey Huang */ 101211f15ed3SMichael Chan if (!ether_addr_equal(resp->mac_address, bp->vf.mac_addr)) 101311f15ed3SMichael Chan memcpy(bp->vf.mac_addr, resp->mac_address, ETH_ALEN); 10143874d6a8SJeffrey Huang 10153874d6a8SJeffrey Huang /* overwrite netdev dev_addr with admin VF MAC */ 10163874d6a8SJeffrey Huang if (is_valid_ether_addr(bp->vf.mac_addr)) 1017379a80a1SMichael Chan memcpy(bp->dev->dev_addr, bp->vf.mac_addr, ETH_ALEN); 1018379a80a1SMichael Chan update_vf_mac_exit: 1019379a80a1SMichael Chan mutex_unlock(&bp->hwrm_cmd_lock); 1020379a80a1SMichael Chan } 1021379a80a1SMichael Chan 102284c33dd3SMichael Chan int bnxt_approve_mac(struct bnxt *bp, u8 *mac) 102384c33dd3SMichael Chan { 102484c33dd3SMichael Chan struct hwrm_func_vf_cfg_input req = {0}; 102584c33dd3SMichael Chan int rc = 0; 102684c33dd3SMichael Chan 102784c33dd3SMichael Chan if (!BNXT_VF(bp)) 102884c33dd3SMichael Chan return 0; 102984c33dd3SMichael Chan 103084c33dd3SMichael Chan if (bp->hwrm_spec_code < 0x10202) { 103184c33dd3SMichael Chan if (is_valid_ether_addr(bp->vf.mac_addr)) 103284c33dd3SMichael Chan rc = -EADDRNOTAVAIL; 103384c33dd3SMichael Chan goto mac_done; 103484c33dd3SMichael Chan } 103584c33dd3SMichael Chan bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_CFG, -1, -1); 103684c33dd3SMichael Chan req.enables = cpu_to_le32(FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR); 103784c33dd3SMichael Chan memcpy(req.dflt_mac_addr, mac, ETH_ALEN); 103884c33dd3SMichael Chan rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 103984c33dd3SMichael Chan mac_done: 104084c33dd3SMichael Chan if (rc) { 104184c33dd3SMichael Chan rc = -EADDRNOTAVAIL; 104284c33dd3SMichael Chan netdev_warn(bp->dev, "VF MAC address %pM not approved by the PF\n", 104384c33dd3SMichael Chan mac); 104484c33dd3SMichael Chan } 104584c33dd3SMichael Chan return rc; 104684c33dd3SMichael Chan } 1047c0c050c5SMichael Chan #else 1048c0c050c5SMichael Chan 1049c0c050c5SMichael Chan void bnxt_sriov_disable(struct bnxt *bp) 1050c0c050c5SMichael Chan { 1051c0c050c5SMichael Chan } 1052c0c050c5SMichael Chan 1053c0c050c5SMichael Chan void bnxt_hwrm_exec_fwd_req(struct bnxt *bp) 1054c0c050c5SMichael Chan { 1055379a80a1SMichael Chan netdev_err(bp->dev, "Invalid VF message received when SRIOV is not enable\n"); 1056379a80a1SMichael Chan } 1057379a80a1SMichael Chan 1058379a80a1SMichael Chan void bnxt_update_vf_mac(struct bnxt *bp) 1059379a80a1SMichael Chan { 1060c0c050c5SMichael Chan } 106184c33dd3SMichael Chan 106284c33dd3SMichael Chan int bnxt_approve_mac(struct bnxt *bp, u8 *mac) 106384c33dd3SMichael Chan { 106484c33dd3SMichael Chan return 0; 106584c33dd3SMichael Chan } 1066c0c050c5SMichael Chan #endif 1067