1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2019-2021 Xilinx, Inc. 4 * Copyright(c) 2019 Solarflare Communications Inc. 5 * 6 * This software was jointly developed between OKTET Labs (under contract 7 * for Solarflare) and Solarflare Communications, Inc. 8 */ 9 10 #include <rte_common.h> 11 #include <rte_bus_pci.h> 12 13 #include "sfc.h" 14 #include "sfc_log.h" 15 16 #include "efx.h" 17 18 19 /* 20 * Check if a MAC address is already assigned to one of previously 21 * configured vPorts (either PF itself or one of already configured VFs). 22 * 23 * Typically the first vPort which corresponds to PF has globally 24 * administered unicast address, but it still could be locally 25 * administered if user assigned it or in the case of unconfigured NIC. 26 * So, it is safer to include it as well in uniqueness check. 27 */ 28 static bool 29 sriov_mac_addr_assigned(const efx_vport_config_t *vport_config, 30 unsigned int num, const uint8_t *mac_addr) 31 { 32 unsigned int i; 33 34 /* Check PF's MAC address as well as explained above */ 35 for (i = 0; i < num; ++i) { 36 if (memcmp(mac_addr, vport_config[i].evc_mac_addr, 37 sizeof(vport_config[i].evc_mac_addr)) == 0) 38 return true; 39 } 40 41 return false; 42 } 43 44 int 45 sfc_sriov_attach(struct sfc_adapter *sa) 46 { 47 const struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(sa->eth_dev); 48 struct sfc_sriov *sriov = &sa->sriov; 49 efx_vport_config_t *vport_config; 50 unsigned int i; 51 int rc; 52 53 sfc_log_init(sa, "entry"); 54 55 sriov->num_vfs = pci_dev->max_vfs; 56 if (sriov->num_vfs == 0) 57 goto done; 58 59 vport_config = calloc(sriov->num_vfs + 1, sizeof(*vport_config)); 60 if (vport_config == NULL) { 61 rc = ENOMEM; 62 goto fail_alloc_vport_config; 63 } 64 65 vport_config[0].evc_function = 0xffff; 66 vport_config[0].evc_vid = EFX_VF_VID_DEFAULT; 67 vport_config[0].evc_vlan_restrict = B_FALSE; 68 69 for (i = 1; i <= sriov->num_vfs; ++i) { 70 vport_config[i].evc_function = i - 1; 71 vport_config[i].evc_vid = EFX_VF_VID_DEFAULT; 72 vport_config[i].evc_vlan_restrict = B_FALSE; 73 do { 74 rte_eth_random_addr(vport_config[i].evc_mac_addr); 75 } while (sriov_mac_addr_assigned(vport_config, i, 76 vport_config[i].evc_mac_addr)); 77 } 78 79 sriov->vport_config = vport_config; 80 81 done: 82 sfc_log_init(sa, "done"); 83 return 0; 84 85 fail_alloc_vport_config: 86 sriov->num_vfs = 0; 87 return rc; 88 } 89 90 void 91 sfc_sriov_detach(struct sfc_adapter *sa) 92 { 93 struct sfc_sriov *sriov = &sa->sriov; 94 95 sfc_log_init(sa, "entry"); 96 97 free(sriov->vport_config); 98 sriov->vport_config = NULL; 99 sriov->num_vfs = 0; 100 101 sfc_log_init(sa, "done"); 102 } 103 104 int 105 sfc_sriov_vswitch_create(struct sfc_adapter *sa) 106 { 107 struct sfc_sriov *sriov = &sa->sriov; 108 efx_vport_config_t *vport_config = sriov->vport_config; 109 int rc; 110 111 sfc_log_init(sa, "entry"); 112 113 if (sriov->num_vfs == 0) { 114 sfc_log_init(sa, "no VFs enabled"); 115 goto done; 116 } 117 118 rc = efx_evb_init(sa->nic); 119 if (rc != 0) { 120 sfc_err(sa, "EVB init failed %d", rc); 121 goto fail_evb_init; 122 } 123 124 RTE_BUILD_BUG_ON(sizeof(sa->port.default_mac_addr) != 125 sizeof(vport_config[0].evc_mac_addr)); 126 rte_ether_addr_copy(&sa->port.default_mac_addr, 127 (struct rte_ether_addr *)vport_config[0].evc_mac_addr); 128 129 rc = efx_evb_vswitch_create(sa->nic, sriov->num_vfs + 1, 130 vport_config, &sriov->vswitch); 131 if (rc != 0) { 132 sfc_err(sa, "EVB vSwitch create failed %d", rc); 133 goto fail_evb_vswitch_create; 134 } 135 136 done: 137 sfc_log_init(sa, "done"); 138 return 0; 139 140 fail_evb_vswitch_create: 141 efx_evb_fini(sa->nic); 142 143 fail_evb_init: 144 return rc; 145 } 146 147 void 148 sfc_sriov_vswitch_destroy(struct sfc_adapter *sa) 149 { 150 struct sfc_sriov *sriov = &sa->sriov; 151 int rc; 152 153 sfc_log_init(sa, "entry"); 154 155 if (sriov->num_vfs == 0) 156 goto done; 157 158 rc = efx_evb_vswitch_destroy(sa->nic, sriov->vswitch); 159 if (rc != 0) 160 sfc_err(sa, "efx_evb_vswitch_destroy() failed %d", rc); 161 162 sriov->vswitch = NULL; 163 164 efx_evb_fini(sa->nic); 165 166 done: 167 sfc_log_init(sa, "done"); 168 } 169