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 (sa->switchdev || 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 (sa->switchdev) { 114 sfc_log_init(sa, "don't create vswitch in switchdev mode"); 115 goto done; 116 } 117 118 if (sriov->num_vfs == 0) { 119 sfc_log_init(sa, "no VFs enabled"); 120 goto done; 121 } 122 123 rc = efx_evb_init(sa->nic); 124 if (rc != 0) { 125 sfc_err(sa, "EVB init failed %d", rc); 126 goto fail_evb_init; 127 } 128 129 RTE_BUILD_BUG_ON(sizeof(sa->port.default_mac_addr) != 130 sizeof(vport_config[0].evc_mac_addr)); 131 rte_ether_addr_copy(&sa->port.default_mac_addr, 132 (struct rte_ether_addr *)vport_config[0].evc_mac_addr); 133 134 rc = efx_evb_vswitch_create(sa->nic, sriov->num_vfs + 1, 135 vport_config, &sriov->vswitch); 136 if (rc != 0) { 137 sfc_err(sa, "EVB vSwitch create failed %d", rc); 138 goto fail_evb_vswitch_create; 139 } 140 141 done: 142 sfc_log_init(sa, "done"); 143 return 0; 144 145 fail_evb_vswitch_create: 146 efx_evb_fini(sa->nic); 147 148 fail_evb_init: 149 return rc; 150 } 151 152 void 153 sfc_sriov_vswitch_destroy(struct sfc_adapter *sa) 154 { 155 struct sfc_sriov *sriov = &sa->sriov; 156 int rc; 157 158 sfc_log_init(sa, "entry"); 159 160 if (sa->switchdev || sriov->num_vfs == 0) 161 goto done; 162 163 rc = efx_evb_vswitch_destroy(sa->nic, sriov->vswitch); 164 if (rc != 0) 165 sfc_err(sa, "efx_evb_vswitch_destroy() failed %d", rc); 166 167 sriov->vswitch = NULL; 168 169 efx_evb_fini(sa->nic); 170 171 done: 172 sfc_log_init(sa, "done"); 173 } 174