xref: /dpdk/drivers/net/sfc/sfc_sriov.c (revision 1f37cb2bb46b1fd403faa7c3bf8884e6a4dfde66)
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 <bus_pci_driver.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
sriov_mac_addr_assigned(const efx_vport_config_t * vport_config,unsigned int num,const uint8_t * mac_addr)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
sfc_sriov_attach(struct sfc_adapter * sa)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
sfc_sriov_detach(struct sfc_adapter * sa)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
sfc_sriov_vswitch_create(struct sfc_adapter * sa)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
sfc_sriov_vswitch_destroy(struct sfc_adapter * sa)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