Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation.
3 : : * Copyright 2013-2014 6WIND S.A.
4 : : */
5 : :
6 : : #include <string.h>
7 : : #include <inttypes.h>
8 : : #include <stdint.h>
9 : : #include <stdbool.h>
10 : : #include <stdlib.h>
11 : : #include <stdio.h>
12 : : #include <sys/queue.h>
13 : : #include <rte_errno.h>
14 : : #include <rte_interrupts.h>
15 : : #include <rte_log.h>
16 : : #include <bus_driver.h>
17 : : #include <rte_pci.h>
18 : : #include <rte_bus_pci.h>
19 : : #include <rte_lcore.h>
20 : : #include <rte_per_lcore.h>
21 : : #include <rte_memory.h>
22 : : #include <rte_eal.h>
23 : : #include <rte_eal_paging.h>
24 : : #include <rte_string_fns.h>
25 : : #include <rte_common.h>
26 : : #include <rte_devargs.h>
27 : : #include <rte_vfio.h>
28 : : #include <rte_tailq.h>
29 : :
30 : : #include "private.h"
31 : :
32 : :
33 : : #define SYSFS_PCI_DEVICES "/sys/bus/pci/devices"
34 : :
35 : 7386 : const char *rte_pci_get_sysfs_path(void)
36 : : {
37 : : const char *path = NULL;
38 : :
39 : : #ifdef RTE_EXEC_ENV_LINUX
40 : 7386 : path = getenv("SYSFS_PCI_DEVICES");
41 [ + - ]: 7386 : if (path == NULL)
42 : 7386 : return SYSFS_PCI_DEVICES;
43 : : #endif
44 : :
45 : : return path;
46 : : }
47 : :
48 : : #ifdef RTE_EXEC_ENV_WINDOWS
49 : : #define asprintf pci_asprintf
50 : :
51 : : static int
52 : : __rte_format_printf(2, 3)
53 : : pci_asprintf(char **buffer, const char *format, ...)
54 : : {
55 : : int size, ret;
56 : : va_list arg;
57 : :
58 : : va_start(arg, format);
59 : : size = vsnprintf(NULL, 0, format, arg);
60 : : va_end(arg);
61 : : if (size < 0)
62 : : return -1;
63 : : size++;
64 : :
65 : : *buffer = malloc(size);
66 : : if (*buffer == NULL)
67 : : return -1;
68 : :
69 : : va_start(arg, format);
70 : : ret = vsnprintf(*buffer, size, format, arg);
71 : : va_end(arg);
72 : : if (ret != size - 1) {
73 : : free(*buffer);
74 : : return -1;
75 : : }
76 : : return ret;
77 : : }
78 : : #endif /* RTE_EXEC_ENV_WINDOWS */
79 : :
80 : : static struct rte_devargs *
81 : 14277 : pci_devargs_lookup(const struct rte_pci_addr *pci_addr)
82 : : {
83 : : struct rte_devargs *devargs;
84 : : struct rte_pci_addr addr;
85 : :
86 [ + + ]: 14620 : RTE_EAL_DEVARGS_FOREACH("pci", devargs) {
87 : 345 : devargs->bus->parse(devargs->name, &addr);
88 [ + + ]: 345 : if (!rte_pci_addr_cmp(pci_addr, &addr))
89 : 2 : return devargs;
90 : : }
91 : : return NULL;
92 : : }
93 : :
94 : : void
95 : 7053 : pci_common_set(struct rte_pci_device *dev)
96 : : {
97 : : struct rte_devargs *devargs;
98 : :
99 : : /* Each device has its internal, canonical name set. */
100 : 7053 : rte_pci_device_name(&dev->addr,
101 : 7053 : dev->name, sizeof(dev->name));
102 : 7053 : devargs = pci_devargs_lookup(&dev->addr);
103 : 7053 : dev->device.devargs = devargs;
104 : :
105 : : /* When using a blocklist, only blocked devices will have
106 : : * an rte_devargs. Allowed devices won't have one.
107 : : */
108 [ + + ]: 7053 : if (devargs != NULL)
109 : : /* If an rte_devargs exists, the generic rte_device uses the
110 : : * given name as its name.
111 : : */
112 : 1 : dev->device.name = dev->device.devargs->name;
113 : : else
114 : : /* Otherwise, it uses the internal, canonical form. */
115 : 7052 : dev->device.name = dev->name;
116 : :
117 [ + - + - ]: 14106 : if (dev->bus_info != NULL ||
118 : 7053 : asprintf(&dev->bus_info, "vendor_id=%"PRIx16", device_id=%"PRIx16,
119 : 7053 : dev->id.vendor_id, dev->id.device_id) != -1)
120 : 7053 : dev->device.bus_info = dev->bus_info;
121 : 7053 : }
122 : :
123 : : void
124 : 7053 : pci_free(struct rte_pci_device_internal *pdev)
125 : : {
126 [ + - ]: 7053 : if (pdev == NULL)
127 : : return;
128 : 7053 : free(pdev->device.bus_info);
129 : 7053 : free(pdev);
130 : : }
131 : :
132 : : /* map a particular resource from a file */
133 : : void *
134 : 0 : pci_map_resource(void *requested_addr, int fd, off_t offset, size_t size,
135 : : int additional_flags)
136 : : {
137 : : void *mapaddr;
138 : :
139 : : /* Map the PCI memory resource of device */
140 : 0 : mapaddr = rte_mem_map(requested_addr, size,
141 : : RTE_PROT_READ | RTE_PROT_WRITE,
142 : : RTE_MAP_SHARED | additional_flags, fd, offset);
143 [ # # ]: 0 : if (mapaddr == NULL) {
144 : 0 : RTE_LOG(ERR, EAL,
145 : : "%s(): cannot map resource(%d, %p, 0x%zx, 0x%llx): %s (%p)\n",
146 : : __func__, fd, requested_addr, size,
147 : : (unsigned long long)offset,
148 : : rte_strerror(rte_errno), mapaddr);
149 : : } else
150 : 0 : RTE_LOG(DEBUG, EAL, " PCI memory mapped at %p\n", mapaddr);
151 : :
152 : 0 : return mapaddr;
153 : : }
154 : :
155 : : /* unmap a particular resource */
156 : : void
157 : 0 : pci_unmap_resource(void *requested_addr, size_t size)
158 : : {
159 [ # # ]: 0 : if (requested_addr == NULL)
160 : : return;
161 : :
162 : : /* Unmap the PCI memory resource of device */
163 [ # # ]: 0 : if (rte_mem_unmap(requested_addr, size)) {
164 : 0 : RTE_LOG(ERR, EAL, "%s(): cannot mem unmap(%p, %#zx): %s\n",
165 : : __func__, requested_addr, size,
166 : : rte_strerror(rte_errno));
167 : : } else
168 : 0 : RTE_LOG(DEBUG, EAL, " PCI memory unmapped at %p\n",
169 : : requested_addr);
170 : : }
171 : : /*
172 : : * Match the PCI Driver and Device using the ID Table
173 : : */
174 : : int
175 : 533372 : rte_pci_match(const struct rte_pci_driver *pci_drv,
176 : : const struct rte_pci_device *pci_dev)
177 : : {
178 : : const struct rte_pci_id *id_table;
179 : :
180 [ + + ]: 5376975 : for (id_table = pci_drv->id_table; id_table->vendor_id != 0;
181 : 4843603 : id_table++) {
182 : : /* check if device's identifiers match the driver's ones */
183 [ + + + - ]: 4843762 : if (id_table->vendor_id != pci_dev->id.vendor_id &&
184 : : id_table->vendor_id != RTE_PCI_ANY_ID)
185 : 4751589 : continue;
186 [ + + + - ]: 92173 : if (id_table->device_id != pci_dev->id.device_id &&
187 : : id_table->device_id != RTE_PCI_ANY_ID)
188 : 92014 : continue;
189 : 159 : if (id_table->subsystem_vendor_id !=
190 [ + - - + ]: 159 : pci_dev->id.subsystem_vendor_id &&
191 : : id_table->subsystem_vendor_id != RTE_PCI_ANY_ID)
192 : 0 : continue;
193 : 159 : if (id_table->subsystem_device_id !=
194 [ + - - + ]: 159 : pci_dev->id.subsystem_device_id &&
195 : : id_table->subsystem_device_id != RTE_PCI_ANY_ID)
196 : 0 : continue;
197 [ + - - + ]: 159 : if (id_table->class_id != pci_dev->id.class_id &&
198 : : id_table->class_id != RTE_CLASS_ANY_ID)
199 : 0 : continue;
200 : :
201 : : return 1;
202 : : }
203 : :
204 : : return 0;
205 : : }
206 : :
207 : : /*
208 : : * If vendor/device ID match, call the probe() function of the
209 : : * driver.
210 : : */
211 : : static int
212 : 533372 : rte_pci_probe_one_driver(struct rte_pci_driver *dr,
213 : : struct rte_pci_device *dev)
214 : : {
215 : : int ret;
216 : : bool already_probed;
217 : : struct rte_pci_addr *loc;
218 : :
219 [ + - ]: 533372 : if ((dr == NULL) || (dev == NULL))
220 : : return -EINVAL;
221 : :
222 : : loc = &dev->addr;
223 : :
224 : : /* The device is not blocked; Check if driver supports it */
225 [ + + ]: 533372 : if (!rte_pci_match(dr, dev))
226 : : /* Match of device and driver failed */
227 : : return 1;
228 : :
229 : 159 : RTE_LOG(DEBUG, EAL, "PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
230 : : loc->domain, loc->bus, loc->devid, loc->function,
231 : : dev->device.numa_node);
232 : :
233 : : /* no initialization when marked as blocked, return without error */
234 [ - + ]: 159 : if (dev->device.devargs != NULL &&
235 [ # # ]: 0 : dev->device.devargs->policy == RTE_DEV_BLOCKED) {
236 : 0 : RTE_LOG(INFO, EAL, " Device is blocked, not initializing\n");
237 : 0 : return 1;
238 : : }
239 : :
240 [ + - + - ]: 159 : if (dev->device.numa_node < 0 && rte_socket_count() > 1)
241 : 159 : RTE_LOG(INFO, EAL, "Device %s is not NUMA-aware\n", dev->name);
242 : :
243 : 159 : already_probed = rte_dev_is_probed(&dev->device);
244 [ - + - - ]: 159 : if (already_probed && !(dr->drv_flags & RTE_PCI_DRV_PROBE_AGAIN)) {
245 : 0 : RTE_LOG(DEBUG, EAL, "Device %s is already probed\n",
246 : : dev->device.name);
247 : 0 : return -EEXIST;
248 : : }
249 : :
250 : 159 : RTE_LOG(DEBUG, EAL, " probe driver: %x:%x %s\n", dev->id.vendor_id,
251 : : dev->id.device_id, dr->driver.name);
252 : :
253 [ + - ]: 159 : if (!already_probed) {
254 : : enum rte_iova_mode dev_iova_mode;
255 : : enum rte_iova_mode iova_mode;
256 : :
257 : 159 : dev_iova_mode = pci_device_iova_mode(dr, dev);
258 : 159 : iova_mode = rte_eal_iova_mode();
259 : 159 : if (dev_iova_mode != RTE_IOVA_DC &&
260 [ - + ]: 159 : dev_iova_mode != iova_mode) {
261 [ # # # # ]: 0 : RTE_LOG(ERR, EAL, " Expecting '%s' IOVA mode but current mode is '%s', not initializing\n",
262 : : dev_iova_mode == RTE_IOVA_PA ? "PA" : "VA",
263 : : iova_mode == RTE_IOVA_PA ? "PA" : "VA");
264 : 0 : return -EINVAL;
265 : : }
266 : :
267 : : /* Allocate interrupt instance for pci device */
268 : 159 : dev->intr_handle =
269 : 159 : rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
270 [ - + ]: 159 : if (dev->intr_handle == NULL) {
271 : 0 : RTE_LOG(ERR, EAL,
272 : : "Failed to create interrupt instance for %s\n",
273 : : dev->device.name);
274 : 0 : return -ENOMEM;
275 : : }
276 : :
277 : 159 : dev->vfio_req_intr_handle =
278 : 159 : rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
279 [ - + ]: 159 : if (dev->vfio_req_intr_handle == NULL) {
280 : 0 : rte_intr_instance_free(dev->intr_handle);
281 : 0 : dev->intr_handle = NULL;
282 : 0 : RTE_LOG(ERR, EAL,
283 : : "Failed to create vfio req interrupt instance for %s\n",
284 : : dev->device.name);
285 : 0 : return -ENOMEM;
286 : : }
287 : :
288 : : /*
289 : : * Reference driver structure.
290 : : * This needs to be before rte_pci_map_device(), as it enables
291 : : * to use driver flags for adjusting configuration.
292 : : */
293 : 159 : dev->driver = dr;
294 [ + - ]: 159 : if (dev->driver->drv_flags & RTE_PCI_DRV_NEED_MAPPING) {
295 : 159 : ret = rte_pci_map_device(dev);
296 [ + - ]: 159 : if (ret != 0) {
297 : 159 : dev->driver = NULL;
298 : 159 : rte_intr_instance_free(dev->vfio_req_intr_handle);
299 : 159 : dev->vfio_req_intr_handle = NULL;
300 : 159 : rte_intr_instance_free(dev->intr_handle);
301 : 159 : dev->intr_handle = NULL;
302 : 159 : return ret;
303 : : }
304 : : }
305 : : }
306 : :
307 : 0 : RTE_LOG(INFO, EAL, "Probe PCI driver: %s (%x:%04x) device: "PCI_PRI_FMT" (socket %i)\n",
308 : : dr->driver.name, dev->id.vendor_id, dev->id.device_id,
309 : : loc->domain, loc->bus, loc->devid, loc->function,
310 : : dev->device.numa_node);
311 : : /* call the driver probe() function */
312 : 0 : ret = dr->probe(dr, dev);
313 [ # # ]: 0 : if (already_probed)
314 : : return ret; /* no rollback if already succeeded earlier */
315 [ # # ]: 0 : if (ret) {
316 : 0 : dev->driver = NULL;
317 [ # # # # ]: 0 : if ((dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING) &&
318 : : /* Don't unmap if device is unsupported and
319 : : * driver needs mapped resources.
320 : : */
321 : 0 : !(ret > 0 &&
322 [ # # ]: 0 : (dr->drv_flags & RTE_PCI_DRV_KEEP_MAPPED_RES)))
323 : 0 : rte_pci_unmap_device(dev);
324 : 0 : rte_intr_instance_free(dev->vfio_req_intr_handle);
325 : 0 : dev->vfio_req_intr_handle = NULL;
326 : 0 : rte_intr_instance_free(dev->intr_handle);
327 : 0 : dev->intr_handle = NULL;
328 : : } else {
329 : 0 : dev->device.driver = &dr->driver;
330 : : }
331 : :
332 : : return ret;
333 : : }
334 : :
335 : : /*
336 : : * If vendor/device ID match, call the remove() function of the
337 : : * driver.
338 : : */
339 : : static int
340 : 0 : rte_pci_detach_dev(struct rte_pci_device *dev)
341 : : {
342 : : struct rte_pci_addr *loc;
343 : : struct rte_pci_driver *dr;
344 : : int ret = 0;
345 : :
346 [ # # ]: 0 : if (dev == NULL)
347 : : return -EINVAL;
348 : :
349 : 0 : dr = dev->driver;
350 : : loc = &dev->addr;
351 : :
352 : 0 : RTE_LOG(DEBUG, EAL, "PCI device "PCI_PRI_FMT" on NUMA socket %i\n",
353 : : loc->domain, loc->bus, loc->devid,
354 : : loc->function, dev->device.numa_node);
355 : :
356 : 0 : RTE_LOG(DEBUG, EAL, " remove driver: %x:%x %s\n", dev->id.vendor_id,
357 : : dev->id.device_id, dr->driver.name);
358 : :
359 [ # # ]: 0 : if (dr->remove) {
360 : 0 : ret = dr->remove(dev);
361 [ # # ]: 0 : if (ret < 0)
362 : : return ret;
363 : : }
364 : :
365 : : /* clear driver structure */
366 : 0 : dev->driver = NULL;
367 : 0 : dev->device.driver = NULL;
368 : :
369 [ # # ]: 0 : if (dr->drv_flags & RTE_PCI_DRV_NEED_MAPPING)
370 : : /* unmap resources for devices that use igb_uio */
371 : 0 : rte_pci_unmap_device(dev);
372 : :
373 : 0 : rte_intr_instance_free(dev->intr_handle);
374 : 0 : dev->intr_handle = NULL;
375 : 0 : rte_intr_instance_free(dev->vfio_req_intr_handle);
376 : 0 : dev->vfio_req_intr_handle = NULL;
377 : :
378 : 0 : return 0;
379 : : }
380 : :
381 : : /*
382 : : * If vendor/device ID match, call the probe() function of all
383 : : * registered driver for the given device. Return < 0 if initialization
384 : : * failed, return 1 if no driver is found for this device.
385 : : */
386 : : static int
387 : 6202 : pci_probe_all_drivers(struct rte_pci_device *dev)
388 : : {
389 : : struct rte_pci_driver *dr = NULL;
390 : : int rc = 0;
391 : :
392 [ + - ]: 6202 : if (dev == NULL)
393 : : return -EINVAL;
394 : :
395 [ + + ]: 539574 : FOREACH_DRIVER_ON_PCIBUS(dr) {
396 : 533372 : rc = rte_pci_probe_one_driver(dr, dev);
397 [ - + ]: 533372 : if (rc < 0)
398 : : /* negative value is an error */
399 : 0 : return rc;
400 [ + - ]: 533372 : if (rc > 0)
401 : : /* positive value means driver doesn't support it */
402 : : continue;
403 : : return 0;
404 : : }
405 : : return 1;
406 : : }
407 : :
408 : : /*
409 : : * Scan the content of the PCI bus, and call the probe() function for
410 : : * all registered drivers that have a matching entry in its id_table
411 : : * for discovered devices.
412 : : */
413 : : static int
414 : 164 : pci_probe(void)
415 : : {
416 : : struct rte_pci_device *dev = NULL;
417 : : size_t probed = 0, failed = 0;
418 : : int ret = 0;
419 : :
420 [ + + ]: 6366 : FOREACH_DEVICE_ON_PCIBUS(dev) {
421 : 6202 : probed++;
422 : :
423 : 6202 : ret = pci_probe_all_drivers(dev);
424 [ - + ]: 6202 : if (ret < 0) {
425 [ # # ]: 0 : if (ret != -EEXIST) {
426 : 0 : RTE_LOG(ERR, EAL, "Requested device "
427 : : PCI_PRI_FMT " cannot be used\n",
428 : : dev->addr.domain, dev->addr.bus,
429 : : dev->addr.devid, dev->addr.function);
430 : 0 : rte_errno = errno;
431 : 0 : failed++;
432 : : }
433 : : ret = 0;
434 : : }
435 : : }
436 : :
437 [ + - ]: 164 : return (probed && probed == failed) ? -1 : 0;
438 : : }
439 : :
440 : : static int
441 : 235 : pci_cleanup(void)
442 : : {
443 : : struct rte_pci_device *dev, *tmp_dev;
444 : : int error = 0;
445 : :
446 [ + + ]: 6632 : RTE_TAILQ_FOREACH_SAFE(dev, &rte_pci_bus.device_list, next, tmp_dev) {
447 : 6397 : struct rte_pci_driver *drv = dev->driver;
448 : : int ret = 0;
449 : :
450 [ - - - + ]: 6397 : if (drv == NULL || drv->remove == NULL)
451 : 6397 : goto free;
452 : :
453 : 0 : ret = drv->remove(dev);
454 [ # # ]: 0 : if (ret < 0) {
455 : 0 : rte_errno = errno;
456 : : error = -1;
457 : : }
458 : 0 : dev->driver = NULL;
459 : 0 : dev->device.driver = NULL;
460 : :
461 : 6397 : free:
462 : : /* free interrupt handles */
463 : 6397 : rte_intr_instance_free(dev->intr_handle);
464 : 6397 : dev->intr_handle = NULL;
465 : 6397 : rte_intr_instance_free(dev->vfio_req_intr_handle);
466 : 6397 : dev->vfio_req_intr_handle = NULL;
467 : :
468 : 6397 : pci_free(RTE_PCI_DEVICE_INTERNAL(dev));
469 : : }
470 : :
471 : 235 : return error;
472 : : }
473 : :
474 : : /* dump one device */
475 : : static int
476 : 0 : pci_dump_one_device(FILE *f, struct rte_pci_device *dev)
477 : : {
478 : : int i;
479 : :
480 : 0 : fprintf(f, PCI_PRI_FMT, dev->addr.domain, dev->addr.bus,
481 : 0 : dev->addr.devid, dev->addr.function);
482 : 0 : fprintf(f, " - vendor:%x device:%x\n", dev->id.vendor_id,
483 : 0 : dev->id.device_id);
484 : :
485 [ # # ]: 0 : for (i = 0; i != sizeof(dev->mem_resource) /
486 : 0 : sizeof(dev->mem_resource[0]); i++) {
487 : 0 : fprintf(f, " %16.16"PRIx64" %16.16"PRIx64"\n",
488 : : dev->mem_resource[i].phys_addr,
489 : : dev->mem_resource[i].len);
490 : : }
491 : 0 : return 0;
492 : : }
493 : :
494 : : /* dump devices on the bus */
495 : : void
496 : 0 : rte_pci_dump(FILE *f)
497 : : {
498 : : struct rte_pci_device *dev = NULL;
499 : :
500 [ # # ]: 0 : FOREACH_DEVICE_ON_PCIBUS(dev) {
501 : 0 : pci_dump_one_device(f, dev);
502 : : }
503 : 0 : }
504 : :
505 : : static int
506 : 379 : pci_parse(const char *name, void *addr)
507 : : {
508 : : struct rte_pci_addr *out = addr;
509 : : struct rte_pci_addr pci_addr;
510 : : bool parse;
511 : :
512 : 379 : parse = (rte_pci_addr_parse(name, &pci_addr) == 0);
513 [ + + ]: 379 : if (parse && addr != NULL)
514 : 345 : *out = pci_addr;
515 : 379 : return parse == false;
516 : : }
517 : :
518 : : /* register a driver */
519 : : void
520 : 20210 : rte_pci_register(struct rte_pci_driver *driver)
521 : : {
522 : 20210 : TAILQ_INSERT_TAIL(&rte_pci_bus.driver_list, driver, next);
523 : 20210 : }
524 : :
525 : : /* unregister a driver */
526 : : void
527 : 235 : rte_pci_unregister(struct rte_pci_driver *driver)
528 : : {
529 [ + - ]: 235 : TAILQ_REMOVE(&rte_pci_bus.driver_list, driver, next);
530 : 235 : }
531 : :
532 : : /* Add a device to PCI bus */
533 : : void
534 : 165 : rte_pci_add_device(struct rte_pci_device *pci_dev)
535 : : {
536 : 165 : TAILQ_INSERT_TAIL(&rte_pci_bus.device_list, pci_dev, next);
537 : 165 : }
538 : :
539 : : /* Insert a device into a predefined position in PCI bus */
540 : : void
541 : 6232 : rte_pci_insert_device(struct rte_pci_device *exist_pci_dev,
542 : : struct rte_pci_device *new_pci_dev)
543 : : {
544 : 6232 : TAILQ_INSERT_BEFORE(exist_pci_dev, new_pci_dev, next);
545 : 6232 : }
546 : :
547 : : /* Remove a device from PCI bus */
548 : : static void
549 : : rte_pci_remove_device(struct rte_pci_device *pci_dev)
550 : : {
551 [ # # ]: 0 : TAILQ_REMOVE(&rte_pci_bus.device_list, pci_dev, next);
552 : : }
553 : :
554 : : static struct rte_device *
555 : 0 : pci_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
556 : : const void *data)
557 : : {
558 : : const struct rte_pci_device *pstart;
559 : : struct rte_pci_device *pdev;
560 : :
561 [ # # ]: 0 : if (start != NULL) {
562 : 0 : pstart = RTE_DEV_TO_PCI_CONST(start);
563 : 0 : pdev = TAILQ_NEXT(pstart, next);
564 : : } else {
565 : 0 : pdev = TAILQ_FIRST(&rte_pci_bus.device_list);
566 : : }
567 [ # # ]: 0 : while (pdev != NULL) {
568 [ # # ]: 0 : if (cmp(&pdev->device, data) == 0)
569 : 0 : return &pdev->device;
570 : 0 : pdev = TAILQ_NEXT(pdev, next);
571 : : }
572 : : return NULL;
573 : : }
574 : :
575 : : /*
576 : : * find the device which encounter the failure, by iterate over all device on
577 : : * PCI bus to check if the memory failure address is located in the range
578 : : * of the BARs of the device.
579 : : */
580 : : static struct rte_pci_device *
581 : 0 : pci_find_device_by_addr(const void *failure_addr)
582 : : {
583 : : struct rte_pci_device *pdev = NULL;
584 : : uint64_t check_point, start, end, len;
585 : : int i;
586 : :
587 : 0 : check_point = (uint64_t)(uintptr_t)failure_addr;
588 : :
589 [ # # ]: 0 : FOREACH_DEVICE_ON_PCIBUS(pdev) {
590 [ # # ]: 0 : for (i = 0; i != RTE_DIM(pdev->mem_resource); i++) {
591 : 0 : start = (uint64_t)(uintptr_t)pdev->mem_resource[i].addr;
592 : 0 : len = pdev->mem_resource[i].len;
593 : 0 : end = start + len;
594 [ # # ]: 0 : if (check_point >= start && check_point < end) {
595 : 0 : RTE_LOG(DEBUG, EAL, "Failure address %16.16"
596 : : PRIx64" belongs to device %s!\n",
597 : : check_point, pdev->device.name);
598 : 0 : return pdev;
599 : : }
600 : : }
601 : : }
602 : : return NULL;
603 : : }
604 : :
605 : : static int
606 : 0 : pci_hot_unplug_handler(struct rte_device *dev)
607 : : {
608 : : struct rte_pci_device *pdev = NULL;
609 : : int ret = 0;
610 : :
611 : 0 : pdev = RTE_DEV_TO_PCI(dev);
612 [ # # ]: 0 : if (!pdev)
613 : : return -1;
614 : :
615 [ # # # ]: 0 : switch (pdev->kdrv) {
616 : : #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
617 : 0 : case RTE_PCI_KDRV_VFIO:
618 : : /*
619 : : * vfio kernel module guaranty the pci device would not be
620 : : * deleted until the user space release the resource, so no
621 : : * need to remap BARs resource here, just directly notify
622 : : * the req event to the user space to handle it.
623 : : */
624 : 0 : rte_dev_event_callback_process(dev->name,
625 : : RTE_DEV_EVENT_REMOVE);
626 : 0 : break;
627 : : #endif
628 : 0 : case RTE_PCI_KDRV_IGB_UIO:
629 : : case RTE_PCI_KDRV_UIO_GENERIC:
630 : : case RTE_PCI_KDRV_NIC_UIO:
631 : : /* BARs resource is invalid, remap it to be safe. */
632 : 0 : ret = pci_uio_remap_resource(pdev);
633 : 0 : break;
634 : 0 : default:
635 : 0 : RTE_LOG(DEBUG, EAL,
636 : : "Not managed by a supported kernel driver, skipped\n");
637 : : ret = -1;
638 : 0 : break;
639 : : }
640 : :
641 : : return ret;
642 : : }
643 : :
644 : : static int
645 : 0 : pci_sigbus_handler(const void *failure_addr)
646 : : {
647 : : struct rte_pci_device *pdev = NULL;
648 : : int ret = 0;
649 : :
650 : 0 : pdev = pci_find_device_by_addr(failure_addr);
651 [ # # ]: 0 : if (!pdev) {
652 : : /* It is a generic sigbus error, no bus would handle it. */
653 : : ret = 1;
654 : : } else {
655 : : /* The sigbus error is caused of hot-unplug. */
656 : 0 : ret = pci_hot_unplug_handler(&pdev->device);
657 [ # # ]: 0 : if (ret) {
658 : 0 : RTE_LOG(ERR, EAL,
659 : : "Failed to handle hot-unplug for device %s",
660 : : pdev->name);
661 : : ret = -1;
662 : : }
663 : : }
664 : 0 : return ret;
665 : : }
666 : :
667 : : static int
668 : 0 : pci_plug(struct rte_device *dev)
669 : : {
670 : 0 : return pci_probe_all_drivers(RTE_DEV_TO_PCI(dev));
671 : : }
672 : :
673 : : static int
674 : 0 : pci_unplug(struct rte_device *dev)
675 : : {
676 : : struct rte_pci_device *pdev;
677 : : int ret;
678 : :
679 : 0 : pdev = RTE_DEV_TO_PCI(dev);
680 : 0 : ret = rte_pci_detach_dev(pdev);
681 [ # # ]: 0 : if (ret == 0) {
682 : : rte_pci_remove_device(pdev);
683 : 0 : rte_devargs_remove(dev->devargs);
684 : 0 : pci_free(RTE_PCI_DEVICE_INTERNAL(pdev));
685 : : }
686 : 0 : return ret;
687 : : }
688 : :
689 : : static int
690 : 0 : pci_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
691 : : {
692 : 0 : struct rte_pci_device *pdev = RTE_DEV_TO_PCI(dev);
693 : :
694 [ # # # # ]: 0 : if (!pdev || !pdev->driver) {
695 : 0 : rte_errno = EINVAL;
696 : 0 : return -1;
697 : : }
698 [ # # ]: 0 : if (pdev->driver->dma_map)
699 : 0 : return pdev->driver->dma_map(pdev, addr, iova, len);
700 : : /**
701 : : * In case driver don't provides any specific mapping
702 : : * try fallback to VFIO.
703 : : */
704 [ # # ]: 0 : if (pdev->kdrv == RTE_PCI_KDRV_VFIO)
705 : 0 : return rte_vfio_container_dma_map
706 : : (RTE_VFIO_DEFAULT_CONTAINER_FD, (uintptr_t)addr,
707 : : iova, len);
708 : 0 : rte_errno = ENOTSUP;
709 : 0 : return -1;
710 : : }
711 : :
712 : : static int
713 : 0 : pci_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
714 : : {
715 : 0 : struct rte_pci_device *pdev = RTE_DEV_TO_PCI(dev);
716 : :
717 [ # # # # ]: 0 : if (!pdev || !pdev->driver) {
718 : 0 : rte_errno = EINVAL;
719 : 0 : return -1;
720 : : }
721 [ # # ]: 0 : if (pdev->driver->dma_unmap)
722 : 0 : return pdev->driver->dma_unmap(pdev, addr, iova, len);
723 : : /**
724 : : * In case driver don't provides any specific mapping
725 : : * try fallback to VFIO.
726 : : */
727 [ # # ]: 0 : if (pdev->kdrv == RTE_PCI_KDRV_VFIO)
728 : 0 : return rte_vfio_container_dma_unmap
729 : : (RTE_VFIO_DEFAULT_CONTAINER_FD, (uintptr_t)addr,
730 : : iova, len);
731 : 0 : rte_errno = ENOTSUP;
732 : 0 : return -1;
733 : : }
734 : :
735 : : bool
736 : 7224 : rte_pci_ignore_device(const struct rte_pci_addr *pci_addr)
737 : : {
738 : 7224 : struct rte_devargs *devargs = pci_devargs_lookup(pci_addr);
739 : :
740 [ + + - ]: 7224 : switch (rte_pci_bus.bus.conf.scan_mode) {
741 : 172 : case RTE_BUS_SCAN_ALLOWLIST:
742 [ + + + - ]: 172 : if (devargs && devargs->policy == RTE_DEV_ALLOWED)
743 : 1 : return false;
744 : : break;
745 : 7052 : case RTE_BUS_SCAN_UNDEFINED:
746 : : case RTE_BUS_SCAN_BLOCKLIST:
747 [ - + - - ]: 7052 : if (devargs == NULL || devargs->policy != RTE_DEV_BLOCKED)
748 : 7052 : return false;
749 : : break;
750 : : }
751 : : return true;
752 : : }
753 : :
754 : : enum rte_iova_mode
755 : 169 : rte_pci_get_iommu_class(void)
756 : : {
757 : : enum rte_iova_mode iova_mode = RTE_IOVA_DC;
758 : : const struct rte_pci_device *dev;
759 : : const struct rte_pci_driver *drv;
760 : : bool devices_want_va = false;
761 : : bool devices_want_pa = false;
762 : : int iommu_no_va = -1;
763 : :
764 [ + + ]: 6566 : FOREACH_DEVICE_ON_PCIBUS(dev) {
765 : : /*
766 : : * We can check this only once, because the IOMMU hardware is
767 : : * the same for all of them.
768 : : */
769 [ + + ]: 6397 : if (iommu_no_va == -1)
770 : 165 : iommu_no_va = pci_device_iommu_support_va(dev)
771 : 165 : ? 0 : 1;
772 : :
773 [ + - ]: 6397 : if (dev->kdrv == RTE_PCI_KDRV_UNKNOWN ||
774 : : dev->kdrv == RTE_PCI_KDRV_NONE)
775 : 6397 : continue;
776 [ # # ]: 0 : FOREACH_DRIVER_ON_PCIBUS(drv) {
777 : : enum rte_iova_mode dev_iova_mode;
778 : :
779 [ # # ]: 0 : if (!rte_pci_match(drv, dev))
780 : 0 : continue;
781 : :
782 : 0 : dev_iova_mode = pci_device_iova_mode(drv, dev);
783 [ # # # # ]: 0 : RTE_LOG(DEBUG, EAL, "PCI driver %s for device "
784 : : PCI_PRI_FMT " wants IOVA as '%s'\n",
785 : : drv->driver.name,
786 : : dev->addr.domain, dev->addr.bus,
787 : : dev->addr.devid, dev->addr.function,
788 : : dev_iova_mode == RTE_IOVA_DC ? "DC" :
789 : : (dev_iova_mode == RTE_IOVA_PA ? "PA" : "VA"));
790 [ # # ]: 0 : if (dev_iova_mode == RTE_IOVA_PA)
791 : : devices_want_pa = true;
792 [ # # ]: 0 : else if (dev_iova_mode == RTE_IOVA_VA)
793 : : devices_want_va = true;
794 : : }
795 : : }
796 [ - + ]: 169 : if (iommu_no_va == 1) {
797 : : iova_mode = RTE_IOVA_PA;
798 [ # # ]: 0 : if (devices_want_va) {
799 : 0 : RTE_LOG(WARNING, EAL, "Some devices want 'VA' but IOMMU does not support 'VA'.\n");
800 : 0 : RTE_LOG(WARNING, EAL, "The devices that want 'VA' won't initialize.\n");
801 : : }
802 [ + - ]: 169 : } else if (devices_want_va && !devices_want_pa) {
803 : : iova_mode = RTE_IOVA_VA;
804 [ + - ]: 169 : } else if (devices_want_pa && !devices_want_va) {
805 : : iova_mode = RTE_IOVA_PA;
806 : : } else {
807 : : iova_mode = RTE_IOVA_DC;
808 [ - + ]: 169 : if (devices_want_va) {
809 : 0 : RTE_LOG(WARNING, EAL, "Some devices want 'VA' but forcing 'DC' because other devices want 'PA'.\n");
810 : 0 : RTE_LOG(WARNING, EAL, "Depending on the final decision by the EAL, not all devices may be able to initialize.\n");
811 : : }
812 : : }
813 : 169 : return iova_mode;
814 : : }
815 : :
816 : : bool
817 : 0 : rte_pci_has_capability_list(const struct rte_pci_device *dev)
818 : : {
819 : : uint16_t status;
820 : :
821 [ # # ]: 0 : if (rte_pci_read_config(dev, &status, sizeof(status), RTE_PCI_STATUS) != sizeof(status))
822 : : return false;
823 : :
824 : 0 : return (status & RTE_PCI_STATUS_CAP_LIST) != 0;
825 : : }
826 : :
827 : : off_t
828 : 0 : rte_pci_find_capability(const struct rte_pci_device *dev, uint8_t cap)
829 : : {
830 : 0 : return rte_pci_find_next_capability(dev, cap, 0);
831 : : }
832 : :
833 : : off_t
834 : 0 : rte_pci_find_next_capability(const struct rte_pci_device *dev, uint8_t cap,
835 : : off_t offset)
836 : : {
837 : : uint8_t pos;
838 : : int ttl;
839 : :
840 [ # # ]: 0 : if (offset == 0)
841 : : offset = RTE_PCI_CAPABILITY_LIST;
842 : : else
843 : 0 : offset += RTE_PCI_CAP_NEXT;
844 : : ttl = (RTE_PCI_CFG_SPACE_SIZE - RTE_PCI_STD_HEADER_SIZEOF) / RTE_PCI_CAP_SIZEOF;
845 : :
846 [ # # ]: 0 : if (rte_pci_read_config(dev, &pos, sizeof(pos), offset) < 0)
847 : : return -1;
848 : :
849 [ # # # # ]: 0 : while (pos && ttl--) {
850 : : uint16_t ent;
851 : : uint8_t id;
852 : :
853 : 0 : offset = pos;
854 [ # # ]: 0 : if (rte_pci_read_config(dev, &ent, sizeof(ent), offset) < 0)
855 : 0 : return -1;
856 : :
857 : 0 : id = ent & 0xff;
858 [ # # ]: 0 : if (id == 0xff)
859 : : break;
860 : :
861 [ # # ]: 0 : if (id == cap)
862 : 0 : return offset;
863 : :
864 : 0 : pos = (ent >> 8);
865 : : }
866 : :
867 : : return 0;
868 : : }
869 : :
870 : : off_t
871 : 0 : rte_pci_find_ext_capability(const struct rte_pci_device *dev, uint32_t cap)
872 : : {
873 : : off_t offset = RTE_PCI_CFG_SPACE_SIZE;
874 : : uint32_t header;
875 : : int ttl;
876 : :
877 : : /* minimum 8 bytes per capability */
878 : : ttl = (RTE_PCI_CFG_SPACE_EXP_SIZE - RTE_PCI_CFG_SPACE_SIZE) / 8;
879 : :
880 [ # # ]: 0 : if (rte_pci_read_config(dev, &header, 4, offset) < 0) {
881 : 0 : RTE_LOG(ERR, EAL, "error in reading extended capabilities\n");
882 : 0 : return -1;
883 : : }
884 : :
885 : : /*
886 : : * If we have no capabilities, this is indicated by cap ID,
887 : : * cap version and next pointer all being 0.
888 : : */
889 [ # # ]: 0 : if (header == 0)
890 : : return 0;
891 : :
892 [ # # ]: 0 : while (ttl != 0) {
893 [ # # ]: 0 : if (RTE_PCI_EXT_CAP_ID(header) == cap)
894 : 0 : return offset;
895 : :
896 : 0 : offset = RTE_PCI_EXT_CAP_NEXT(header);
897 : :
898 [ # # ]: 0 : if (offset < RTE_PCI_CFG_SPACE_SIZE)
899 : : break;
900 : :
901 [ # # ]: 0 : if (rte_pci_read_config(dev, &header, 4, offset) < 0) {
902 : 0 : RTE_LOG(ERR, EAL,
903 : : "error in reading extended capabilities\n");
904 : 0 : return -1;
905 : : }
906 : :
907 : 0 : ttl--;
908 : : }
909 : :
910 : : return 0;
911 : : }
912 : :
913 : : int
914 : 0 : rte_pci_set_bus_master(const struct rte_pci_device *dev, bool enable)
915 : : {
916 : : uint16_t old_cmd, cmd;
917 : :
918 [ # # ]: 0 : if (rte_pci_read_config(dev, &old_cmd, sizeof(old_cmd),
919 : : RTE_PCI_COMMAND) < 0) {
920 : 0 : RTE_LOG(ERR, EAL, "error in reading PCI command register\n");
921 : 0 : return -1;
922 : : }
923 : :
924 [ # # ]: 0 : if (enable)
925 : 0 : cmd = old_cmd | RTE_PCI_COMMAND_MASTER;
926 : : else
927 : 0 : cmd = old_cmd & ~RTE_PCI_COMMAND_MASTER;
928 : :
929 [ # # ]: 0 : if (cmd == old_cmd)
930 : : return 0;
931 : :
932 [ # # ]: 0 : if (rte_pci_write_config(dev, &cmd, sizeof(cmd),
933 : : RTE_PCI_COMMAND) < 0) {
934 : 0 : RTE_LOG(ERR, EAL, "error in writing PCI command register\n");
935 : 0 : return -1;
936 : : }
937 : :
938 : : return 0;
939 : : }
940 : :
941 : : int
942 : 0 : rte_pci_pasid_set_state(const struct rte_pci_device *dev,
943 : : off_t offset, bool enable)
944 : : {
945 : 0 : uint16_t pasid = enable;
946 : 0 : return rte_pci_write_config(dev, &pasid, sizeof(pasid),
947 [ # # ]: 0 : offset + RTE_PCI_PASID_CTRL) != sizeof(pasid) ? -1 : 0;
948 : : }
949 : :
950 : : struct rte_pci_bus rte_pci_bus = {
951 : : .bus = {
952 : : .scan = rte_pci_scan,
953 : : .probe = pci_probe,
954 : : .cleanup = pci_cleanup,
955 : : .find_device = pci_find_device,
956 : : .plug = pci_plug,
957 : : .unplug = pci_unplug,
958 : : .parse = pci_parse,
959 : : .devargs_parse = rte_pci_devargs_parse,
960 : : .dma_map = pci_dma_map,
961 : : .dma_unmap = pci_dma_unmap,
962 : : .get_iommu_class = rte_pci_get_iommu_class,
963 : : .dev_iterate = rte_pci_dev_iterate,
964 : : .hot_unplug_handler = pci_hot_unplug_handler,
965 : : .sigbus_handler = pci_sigbus_handler,
966 : : },
967 : : .device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
968 : : .driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
969 : : };
970 : :
971 : 235 : RTE_REGISTER_BUS(pci, rte_pci_bus.bus);
|