Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2020-2021 Xilinx, Inc.
3 : : */
4 : :
5 : : #include <stdbool.h>
6 : : #include <stdint.h>
7 : : #include <pthread.h>
8 : : #include <sys/queue.h>
9 : :
10 : : #include <rte_common.h>
11 : : #include <rte_devargs.h>
12 : : #include <rte_errno.h>
13 : : #include <rte_kvargs.h>
14 : : #include <rte_string_fns.h>
15 : : #include <rte_vfio.h>
16 : : #include <rte_vhost.h>
17 : :
18 : : #include "efx.h"
19 : : #include "sfc_efx.h"
20 : : #include "sfc_vdpa.h"
21 : :
22 : : TAILQ_HEAD(sfc_vdpa_adapter_list_head, sfc_vdpa_adapter);
23 : : static struct sfc_vdpa_adapter_list_head sfc_vdpa_adapter_list =
24 : : TAILQ_HEAD_INITIALIZER(sfc_vdpa_adapter_list);
25 : :
26 : : static pthread_mutex_t sfc_vdpa_adapter_list_lock = PTHREAD_MUTEX_INITIALIZER;
27 : :
28 : : struct sfc_vdpa_adapter *
29 : 0 : sfc_vdpa_get_adapter_by_dev(struct rte_pci_device *pdev)
30 : : {
31 : : bool found = false;
32 : : struct sfc_vdpa_adapter *sva;
33 : :
34 : 0 : pthread_mutex_lock(&sfc_vdpa_adapter_list_lock);
35 : :
36 [ # # ]: 0 : TAILQ_FOREACH(sva, &sfc_vdpa_adapter_list, next) {
37 [ # # ]: 0 : if (pdev == sva->pdev) {
38 : : found = true;
39 : : break;
40 : : }
41 : : }
42 : :
43 : 0 : pthread_mutex_unlock(&sfc_vdpa_adapter_list_lock);
44 : :
45 [ # # ]: 0 : return found ? sva : NULL;
46 : : }
47 : :
48 : : struct sfc_vdpa_ops_data *
49 : 0 : sfc_vdpa_get_data_by_dev(struct rte_vdpa_device *vdpa_dev)
50 : : {
51 : : bool found = false;
52 : : struct sfc_vdpa_adapter *sva;
53 : :
54 : 0 : pthread_mutex_lock(&sfc_vdpa_adapter_list_lock);
55 : :
56 [ # # ]: 0 : TAILQ_FOREACH(sva, &sfc_vdpa_adapter_list, next) {
57 [ # # ]: 0 : if (vdpa_dev == sva->ops_data->vdpa_dev) {
58 : : found = true;
59 : : break;
60 : : }
61 : : }
62 : :
63 : 0 : pthread_mutex_unlock(&sfc_vdpa_adapter_list_lock);
64 : :
65 [ # # ]: 0 : return found ? sva->ops_data : NULL;
66 : : }
67 : :
68 : : static int
69 : 0 : sfc_vdpa_vfio_setup(struct sfc_vdpa_adapter *sva)
70 : : {
71 : 0 : struct rte_pci_device *dev = sva->pdev;
72 : 0 : char dev_name[RTE_DEV_NAME_MAX_LEN] = {0};
73 : : int rc;
74 : :
75 : 0 : rte_pci_device_name(&dev->addr, dev_name, RTE_DEV_NAME_MAX_LEN);
76 : :
77 : 0 : sva->vfio_container_fd = rte_vfio_container_create();
78 [ # # ]: 0 : if (sva->vfio_container_fd < 0) {
79 : 0 : sfc_vdpa_err(sva, "failed to create VFIO container");
80 : 0 : goto fail_container_create;
81 : : }
82 : :
83 : 0 : rc = rte_vfio_get_group_num(rte_pci_get_sysfs_path(), dev_name,
84 : : &sva->iommu_group_num);
85 [ # # ]: 0 : if (rc <= 0) {
86 : 0 : sfc_vdpa_err(sva, "failed to get IOMMU group for %s : %s",
87 : : dev_name, rte_strerror(-rc));
88 : 0 : goto fail_get_group_num;
89 : : }
90 : :
91 : 0 : sva->vfio_group_fd =
92 : 0 : rte_vfio_container_group_bind(sva->vfio_container_fd,
93 : : sva->iommu_group_num);
94 [ # # ]: 0 : if (sva->vfio_group_fd < 0) {
95 : 0 : sfc_vdpa_err(sva,
96 : : "failed to bind IOMMU group %d to container %d",
97 : : sva->iommu_group_num, sva->vfio_container_fd);
98 : 0 : goto fail_group_bind;
99 : : }
100 : :
101 [ # # ]: 0 : if (rte_pci_map_device(dev) != 0) {
102 : 0 : sfc_vdpa_err(sva, "failed to map PCI device %s : %s",
103 : : dev_name, rte_strerror(rte_errno));
104 : 0 : goto fail_pci_map_device;
105 : : }
106 : :
107 : 0 : sva->vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
108 : :
109 : 0 : return 0;
110 : :
111 : : fail_pci_map_device:
112 [ # # ]: 0 : if (rte_vfio_container_group_unbind(sva->vfio_container_fd,
113 : : sva->iommu_group_num) != 0) {
114 : 0 : sfc_vdpa_err(sva,
115 : : "failed to unbind IOMMU group %d from container %d",
116 : : sva->iommu_group_num, sva->vfio_container_fd);
117 : : }
118 : :
119 : 0 : fail_group_bind:
120 : 0 : fail_get_group_num:
121 [ # # ]: 0 : if (rte_vfio_container_destroy(sva->vfio_container_fd) != 0) {
122 : 0 : sfc_vdpa_err(sva, "failed to destroy container %d",
123 : : sva->vfio_container_fd);
124 : : }
125 : :
126 : 0 : fail_container_create:
127 : : return -1;
128 : : }
129 : :
130 : : static void
131 : 0 : sfc_vdpa_vfio_teardown(struct sfc_vdpa_adapter *sva)
132 : : {
133 : 0 : rte_pci_unmap_device(sva->pdev);
134 : :
135 [ # # ]: 0 : if (rte_vfio_container_group_unbind(sva->vfio_container_fd,
136 : : sva->iommu_group_num) != 0) {
137 : 0 : sfc_vdpa_err(sva,
138 : : "failed to unbind IOMMU group %d from container %d",
139 : : sva->iommu_group_num, sva->vfio_container_fd);
140 : : }
141 : :
142 [ # # ]: 0 : if (rte_vfio_container_destroy(sva->vfio_container_fd) != 0) {
143 : 0 : sfc_vdpa_err(sva,
144 : : "failed to destroy container %d",
145 : : sva->vfio_container_fd);
146 : : }
147 : 0 : }
148 : :
149 : : static int
150 : 0 : sfc_vdpa_set_log_prefix(struct sfc_vdpa_adapter *sva)
151 : : {
152 : 0 : struct rte_pci_device *pci_dev = sva->pdev;
153 : : int ret;
154 : :
155 : 0 : ret = snprintf(sva->log_prefix, sizeof(sva->log_prefix),
156 : : "PMD: sfc_vdpa " PCI_PRI_FMT " : ",
157 : 0 : pci_dev->addr.domain, pci_dev->addr.bus,
158 [ # # ]: 0 : pci_dev->addr.devid, pci_dev->addr.function);
159 : :
160 [ # # ]: 0 : if (ret < 0 || ret >= (int)sizeof(sva->log_prefix)) {
161 : 0 : SFC_VDPA_GENERIC_LOG(ERR,
162 : : "reserved log prefix is too short for " PCI_PRI_FMT,
163 : : pci_dev->addr.domain, pci_dev->addr.bus,
164 : : pci_dev->addr.devid, pci_dev->addr.function);
165 : 0 : return -EINVAL;
166 : : }
167 : :
168 : : return 0;
169 : : }
170 : :
171 : : uint32_t
172 : 0 : sfc_vdpa_register_logtype(const struct rte_pci_addr *pci_addr,
173 : : const char *lt_prefix_str, uint32_t ll_default)
174 : : {
175 : 0 : size_t lt_prefix_str_size = strlen(lt_prefix_str);
176 : : size_t lt_str_size_max;
177 : : char *lt_str = NULL;
178 : : int ret;
179 : :
180 : : if (SIZE_MAX - PCI_PRI_STR_SIZE - 1 > lt_prefix_str_size) {
181 : 0 : ++lt_prefix_str_size; /* Reserve space for prefix separator */
182 : 0 : lt_str_size_max = lt_prefix_str_size + PCI_PRI_STR_SIZE + 1;
183 : : } else {
184 : : return sfc_vdpa_logtype_driver;
185 : : }
186 : :
187 : 0 : lt_str = rte_zmalloc("logtype_str", lt_str_size_max, 0);
188 [ # # ]: 0 : if (lt_str == NULL)
189 : 0 : return sfc_vdpa_logtype_driver;
190 : :
191 : : strncpy(lt_str, lt_prefix_str, lt_prefix_str_size);
192 : 0 : lt_str[lt_prefix_str_size - 1] = '.';
193 : 0 : rte_pci_device_name(pci_addr, lt_str + lt_prefix_str_size,
194 : : lt_str_size_max - lt_prefix_str_size);
195 : 0 : lt_str[lt_str_size_max - 1] = '\0';
196 : :
197 : 0 : ret = rte_log_register_type_and_pick_level(lt_str, ll_default);
198 : 0 : rte_free(lt_str);
199 : :
200 [ # # ]: 0 : return ret < 0 ? sfc_vdpa_logtype_driver : ret;
201 : : }
202 : :
203 : : static int
204 : 0 : sfc_vdpa_kvargs_parse(struct sfc_vdpa_adapter *sva)
205 : : {
206 : 0 : struct rte_pci_device *pci_dev = sva->pdev;
207 : 0 : struct rte_devargs *devargs = pci_dev->device.devargs;
208 : : /*
209 : : * To get the device class a mandatory param 'class' is being
210 : : * used so included SFC_EFX_KVARG_DEV_CLASS in the param list.
211 : : */
212 : 0 : const char **params = (const char *[]){
213 : : RTE_DEVARGS_KEY_CLASS,
214 : : SFC_VDPA_MAC_ADDR,
215 : : NULL,
216 : : };
217 : :
218 [ # # ]: 0 : if (devargs == NULL)
219 : : return 0;
220 : :
221 : 0 : sva->kvargs = rte_kvargs_parse(devargs->args, params);
222 [ # # ]: 0 : if (sva->kvargs == NULL)
223 : 0 : return -EINVAL;
224 : :
225 : : return 0;
226 : : }
227 : :
228 : : static struct rte_pci_id pci_id_sfc_vdpa_efx_map[] = {
229 : : { RTE_PCI_DEVICE(EFX_PCI_VENID_XILINX, EFX_PCI_DEVID_RIVERHEAD_VF) },
230 : : { .vendor_id = 0, /* sentinel */ },
231 : : };
232 : :
233 : : static int
234 : 0 : sfc_vdpa_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
235 : : struct rte_pci_device *pci_dev)
236 : : {
237 : : struct sfc_vdpa_adapter *sva = NULL;
238 : : uint32_t logtype_main;
239 : : int ret = 0;
240 : :
241 [ # # ]: 0 : if (sfc_efx_dev_class_get(pci_dev->device.devargs) !=
242 : : SFC_EFX_DEV_CLASS_VDPA) {
243 : 0 : SFC_VDPA_GENERIC_LOG(INFO,
244 : : "Incompatible device class: skip probing, should be probed by other sfc driver.");
245 : 0 : return 1;
246 : : }
247 : :
248 : : /*
249 : : * It will not be probed in the secondary process. As device class
250 : : * is vdpa so return 0 to avoid probe by other sfc driver
251 : : */
252 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
253 : : return 0;
254 : :
255 : 0 : logtype_main = sfc_vdpa_register_logtype(&pci_dev->addr,
256 : : SFC_VDPA_LOGTYPE_MAIN_STR,
257 : : RTE_LOG_NOTICE);
258 : :
259 : 0 : sva = rte_zmalloc("sfc_vdpa", sizeof(struct sfc_vdpa_adapter), 0);
260 [ # # ]: 0 : if (sva == NULL)
261 : 0 : goto fail_zmalloc;
262 : :
263 : 0 : sva->pdev = pci_dev;
264 : 0 : sva->logtype_main = logtype_main;
265 : :
266 : 0 : ret = sfc_vdpa_set_log_prefix(sva);
267 [ # # ]: 0 : if (ret != 0)
268 : 0 : goto fail_set_log_prefix;
269 : :
270 : 0 : ret = sfc_vdpa_kvargs_parse(sva);
271 [ # # ]: 0 : if (ret != 0)
272 : 0 : goto fail_kvargs_parse;
273 : :
274 : 0 : sfc_vdpa_log_init(sva, "entry");
275 : :
276 : : sfc_vdpa_adapter_lock_init(sva);
277 : :
278 : 0 : sfc_vdpa_log_init(sva, "vfio init");
279 [ # # ]: 0 : if (sfc_vdpa_vfio_setup(sva) < 0) {
280 : 0 : sfc_vdpa_err(sva, "failed to setup device %s", pci_dev->name);
281 : 0 : goto fail_vfio_setup;
282 : : }
283 : :
284 : 0 : sfc_vdpa_log_init(sva, "hw init");
285 [ # # ]: 0 : if (sfc_vdpa_hw_init(sva) != 0) {
286 : 0 : sfc_vdpa_err(sva, "failed to init HW %s", pci_dev->name);
287 : 0 : goto fail_hw_init;
288 : : }
289 : :
290 : 0 : sfc_vdpa_log_init(sva, "dev init");
291 : 0 : sva->ops_data = sfc_vdpa_device_init(sva, SFC_VDPA_AS_VF);
292 [ # # ]: 0 : if (sva->ops_data == NULL) {
293 : 0 : sfc_vdpa_err(sva, "failed vDPA dev init %s", pci_dev->name);
294 : 0 : goto fail_dev_init;
295 : : }
296 : :
297 : 0 : pthread_mutex_lock(&sfc_vdpa_adapter_list_lock);
298 : 0 : TAILQ_INSERT_TAIL(&sfc_vdpa_adapter_list, sva, next);
299 : 0 : pthread_mutex_unlock(&sfc_vdpa_adapter_list_lock);
300 : :
301 : 0 : sfc_vdpa_log_init(sva, "done");
302 : :
303 : 0 : return 0;
304 : :
305 : : fail_dev_init:
306 : 0 : sfc_vdpa_hw_fini(sva);
307 : :
308 : 0 : fail_hw_init:
309 : 0 : sfc_vdpa_vfio_teardown(sva);
310 : :
311 : 0 : fail_vfio_setup:
312 : : sfc_vdpa_adapter_lock_fini(sva);
313 : :
314 : 0 : fail_kvargs_parse:
315 : 0 : fail_set_log_prefix:
316 : 0 : rte_free(sva);
317 : :
318 : : fail_zmalloc:
319 : : return -1;
320 : : }
321 : :
322 : : static int
323 : 0 : sfc_vdpa_pci_remove(struct rte_pci_device *pci_dev)
324 : : {
325 : : struct sfc_vdpa_adapter *sva = NULL;
326 : :
327 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
328 : : return -1;
329 : :
330 : 0 : sva = sfc_vdpa_get_adapter_by_dev(pci_dev);
331 [ # # ]: 0 : if (sva == NULL) {
332 : 0 : SFC_VDPA_GENERIC_LOG(INFO,
333 : : "Invalid device: %s.", pci_dev->name);
334 : 0 : return -1;
335 : : }
336 : :
337 : 0 : pthread_mutex_lock(&sfc_vdpa_adapter_list_lock);
338 [ # # ]: 0 : TAILQ_REMOVE(&sfc_vdpa_adapter_list, sva, next);
339 : 0 : pthread_mutex_unlock(&sfc_vdpa_adapter_list_lock);
340 : :
341 : 0 : sfc_vdpa_device_fini(sva->ops_data);
342 : :
343 : 0 : sfc_vdpa_hw_fini(sva);
344 : :
345 : 0 : sfc_vdpa_vfio_teardown(sva);
346 : :
347 : : sfc_vdpa_adapter_lock_fini(sva);
348 : :
349 : 0 : rte_free(sva);
350 : :
351 : 0 : return 0;
352 : : }
353 : :
354 : : static struct rte_pci_driver rte_sfc_vdpa = {
355 : : .id_table = pci_id_sfc_vdpa_efx_map,
356 : : .drv_flags = 0,
357 : : .probe = sfc_vdpa_pci_probe,
358 : : .remove = sfc_vdpa_pci_remove,
359 : : };
360 : :
361 : 251 : RTE_PMD_REGISTER_PCI(net_sfc_vdpa, rte_sfc_vdpa);
362 : : RTE_PMD_REGISTER_PCI_TABLE(net_sfc_vdpa, pci_id_sfc_vdpa_efx_map);
363 : : RTE_PMD_REGISTER_KMOD_DEP(net_sfc_vdpa, "* vfio-pci");
364 [ - + ]: 251 : RTE_LOG_REGISTER_SUFFIX(sfc_vdpa_logtype_driver, driver, NOTICE);
|