xref: /dpdk/drivers/bus/pci/linux/pci.c (revision 89f0711f9ddfb5822da9d34f384b92f72a61c4dc)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4 
5 #include <string.h>
6 #include <dirent.h>
7 
8 #include <rte_log.h>
9 #include <rte_bus.h>
10 #include <rte_pci.h>
11 #include <rte_bus_pci.h>
12 #include <rte_eal_memconfig.h>
13 #include <rte_malloc.h>
14 #include <rte_devargs.h>
15 #include <rte_memcpy.h>
16 #include <rte_vfio.h>
17 
18 #include "eal_private.h"
19 #include "eal_filesystem.h"
20 
21 #include "private.h"
22 #include "pci_init.h"
23 
24 /**
25  * @file
26  * PCI probing under linux
27  *
28  * This code is used to simulate a PCI probe by parsing information in sysfs.
29  * When a registered device matches a driver, it is then initialized with
30  * IGB_UIO driver (or doesn't initialize, if the device wasn't bound to it).
31  */
32 
33 extern struct rte_pci_bus rte_pci_bus;
34 
35 static int
36 pci_get_kernel_driver_by_path(const char *filename, char *dri_name)
37 {
38 	int count;
39 	char path[PATH_MAX];
40 	char *name;
41 
42 	if (!filename || !dri_name)
43 		return -1;
44 
45 	count = readlink(filename, path, PATH_MAX);
46 	if (count >= PATH_MAX)
47 		return -1;
48 
49 	/* For device does not have a driver */
50 	if (count < 0)
51 		return 1;
52 
53 	path[count] = '\0';
54 
55 	name = strrchr(path, '/');
56 	if (name) {
57 		strncpy(dri_name, name + 1, strlen(name + 1) + 1);
58 		return 0;
59 	}
60 
61 	return -1;
62 }
63 
64 /* Map pci device */
65 int
66 rte_pci_map_device(struct rte_pci_device *dev)
67 {
68 	int ret = -1;
69 
70 	/* try mapping the NIC resources using VFIO if it exists */
71 	switch (dev->kdrv) {
72 	case RTE_KDRV_VFIO:
73 #ifdef VFIO_PRESENT
74 		if (pci_vfio_is_enabled())
75 			ret = pci_vfio_map_resource(dev);
76 #endif
77 		break;
78 	case RTE_KDRV_IGB_UIO:
79 	case RTE_KDRV_UIO_GENERIC:
80 		if (rte_eal_using_phys_addrs()) {
81 			/* map resources for devices that use uio */
82 			ret = pci_uio_map_resource(dev);
83 		}
84 		break;
85 	default:
86 		RTE_LOG(DEBUG, EAL,
87 			"  Not managed by a supported kernel driver, skipped\n");
88 		ret = 1;
89 		break;
90 	}
91 
92 	return ret;
93 }
94 
95 /* Unmap pci device */
96 void
97 rte_pci_unmap_device(struct rte_pci_device *dev)
98 {
99 	/* try unmapping the NIC resources using VFIO if it exists */
100 	switch (dev->kdrv) {
101 	case RTE_KDRV_VFIO:
102 #ifdef VFIO_PRESENT
103 		if (pci_vfio_is_enabled())
104 			pci_vfio_unmap_resource(dev);
105 #endif
106 		break;
107 	case RTE_KDRV_IGB_UIO:
108 	case RTE_KDRV_UIO_GENERIC:
109 		/* unmap resources for devices that use uio */
110 		pci_uio_unmap_resource(dev);
111 		break;
112 	default:
113 		RTE_LOG(DEBUG, EAL,
114 			"  Not managed by a supported kernel driver, skipped\n");
115 		break;
116 	}
117 }
118 
119 void *
120 pci_find_max_end_va(void)
121 {
122 	const struct rte_memseg *seg = rte_eal_get_physmem_layout();
123 	const struct rte_memseg *last = seg;
124 	unsigned i = 0;
125 
126 	for (i = 0; i < RTE_MAX_MEMSEG; i++, seg++) {
127 		if (seg->addr == NULL)
128 			break;
129 
130 		if (seg->addr > last->addr)
131 			last = seg;
132 
133 	}
134 	return RTE_PTR_ADD(last->addr, last->len);
135 }
136 
137 /* parse one line of the "resource" sysfs file (note that the 'line'
138  * string is modified)
139  */
140 int
141 pci_parse_one_sysfs_resource(char *line, size_t len, uint64_t *phys_addr,
142 	uint64_t *end_addr, uint64_t *flags)
143 {
144 	union pci_resource_info {
145 		struct {
146 			char *phys_addr;
147 			char *end_addr;
148 			char *flags;
149 		};
150 		char *ptrs[PCI_RESOURCE_FMT_NVAL];
151 	} res_info;
152 
153 	if (rte_strsplit(line, len, res_info.ptrs, 3, ' ') != 3) {
154 		RTE_LOG(ERR, EAL,
155 			"%s(): bad resource format\n", __func__);
156 		return -1;
157 	}
158 	errno = 0;
159 	*phys_addr = strtoull(res_info.phys_addr, NULL, 16);
160 	*end_addr = strtoull(res_info.end_addr, NULL, 16);
161 	*flags = strtoull(res_info.flags, NULL, 16);
162 	if (errno != 0) {
163 		RTE_LOG(ERR, EAL,
164 			"%s(): bad resource format\n", __func__);
165 		return -1;
166 	}
167 
168 	return 0;
169 }
170 
171 /* parse the "resource" sysfs file */
172 static int
173 pci_parse_sysfs_resource(const char *filename, struct rte_pci_device *dev)
174 {
175 	FILE *f;
176 	char buf[BUFSIZ];
177 	int i;
178 	uint64_t phys_addr, end_addr, flags;
179 
180 	f = fopen(filename, "r");
181 	if (f == NULL) {
182 		RTE_LOG(ERR, EAL, "Cannot open sysfs resource\n");
183 		return -1;
184 	}
185 
186 	for (i = 0; i<PCI_MAX_RESOURCE; i++) {
187 
188 		if (fgets(buf, sizeof(buf), f) == NULL) {
189 			RTE_LOG(ERR, EAL,
190 				"%s(): cannot read resource\n", __func__);
191 			goto error;
192 		}
193 		if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr,
194 				&end_addr, &flags) < 0)
195 			goto error;
196 
197 		if (flags & IORESOURCE_MEM) {
198 			dev->mem_resource[i].phys_addr = phys_addr;
199 			dev->mem_resource[i].len = end_addr - phys_addr + 1;
200 			/* not mapped for now */
201 			dev->mem_resource[i].addr = NULL;
202 		}
203 	}
204 	fclose(f);
205 	return 0;
206 
207 error:
208 	fclose(f);
209 	return -1;
210 }
211 
212 /* Scan one pci sysfs entry, and fill the devices list from it. */
213 static int
214 pci_scan_one(const char *dirname, const struct rte_pci_addr *addr)
215 {
216 	char filename[PATH_MAX];
217 	unsigned long tmp;
218 	struct rte_pci_device *dev;
219 	char driver[PATH_MAX];
220 	int ret;
221 
222 	dev = malloc(sizeof(*dev));
223 	if (dev == NULL)
224 		return -1;
225 
226 	memset(dev, 0, sizeof(*dev));
227 	dev->addr = *addr;
228 
229 	/* get vendor id */
230 	snprintf(filename, sizeof(filename), "%s/vendor", dirname);
231 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
232 		free(dev);
233 		return -1;
234 	}
235 	dev->id.vendor_id = (uint16_t)tmp;
236 
237 	/* get device id */
238 	snprintf(filename, sizeof(filename), "%s/device", dirname);
239 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
240 		free(dev);
241 		return -1;
242 	}
243 	dev->id.device_id = (uint16_t)tmp;
244 
245 	/* get subsystem_vendor id */
246 	snprintf(filename, sizeof(filename), "%s/subsystem_vendor",
247 		 dirname);
248 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
249 		free(dev);
250 		return -1;
251 	}
252 	dev->id.subsystem_vendor_id = (uint16_t)tmp;
253 
254 	/* get subsystem_device id */
255 	snprintf(filename, sizeof(filename), "%s/subsystem_device",
256 		 dirname);
257 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
258 		free(dev);
259 		return -1;
260 	}
261 	dev->id.subsystem_device_id = (uint16_t)tmp;
262 
263 	/* get class_id */
264 	snprintf(filename, sizeof(filename), "%s/class",
265 		 dirname);
266 	if (eal_parse_sysfs_value(filename, &tmp) < 0) {
267 		free(dev);
268 		return -1;
269 	}
270 	/* the least 24 bits are valid: class, subclass, program interface */
271 	dev->id.class_id = (uint32_t)tmp & RTE_CLASS_ANY_ID;
272 
273 	/* get max_vfs */
274 	dev->max_vfs = 0;
275 	snprintf(filename, sizeof(filename), "%s/max_vfs", dirname);
276 	if (!access(filename, F_OK) &&
277 	    eal_parse_sysfs_value(filename, &tmp) == 0)
278 		dev->max_vfs = (uint16_t)tmp;
279 	else {
280 		/* for non igb_uio driver, need kernel version >= 3.8 */
281 		snprintf(filename, sizeof(filename),
282 			 "%s/sriov_numvfs", dirname);
283 		if (!access(filename, F_OK) &&
284 		    eal_parse_sysfs_value(filename, &tmp) == 0)
285 			dev->max_vfs = (uint16_t)tmp;
286 	}
287 
288 	/* get numa node, default to 0 if not present */
289 	snprintf(filename, sizeof(filename), "%s/numa_node",
290 		 dirname);
291 
292 	if (access(filename, F_OK) != -1) {
293 		if (eal_parse_sysfs_value(filename, &tmp) == 0)
294 			dev->device.numa_node = tmp;
295 		else
296 			dev->device.numa_node = -1;
297 	} else {
298 		dev->device.numa_node = 0;
299 	}
300 
301 	pci_name_set(dev);
302 
303 	/* parse resources */
304 	snprintf(filename, sizeof(filename), "%s/resource", dirname);
305 	if (pci_parse_sysfs_resource(filename, dev) < 0) {
306 		RTE_LOG(ERR, EAL, "%s(): cannot parse resource\n", __func__);
307 		free(dev);
308 		return -1;
309 	}
310 
311 	/* parse driver */
312 	snprintf(filename, sizeof(filename), "%s/driver", dirname);
313 	ret = pci_get_kernel_driver_by_path(filename, driver);
314 	if (ret < 0) {
315 		RTE_LOG(ERR, EAL, "Fail to get kernel driver\n");
316 		free(dev);
317 		return -1;
318 	}
319 
320 	if (!ret) {
321 		if (!strcmp(driver, "vfio-pci"))
322 			dev->kdrv = RTE_KDRV_VFIO;
323 		else if (!strcmp(driver, "igb_uio"))
324 			dev->kdrv = RTE_KDRV_IGB_UIO;
325 		else if (!strcmp(driver, "uio_pci_generic"))
326 			dev->kdrv = RTE_KDRV_UIO_GENERIC;
327 		else
328 			dev->kdrv = RTE_KDRV_UNKNOWN;
329 	} else
330 		dev->kdrv = RTE_KDRV_NONE;
331 
332 	/* device is valid, add in list (sorted) */
333 	if (TAILQ_EMPTY(&rte_pci_bus.device_list)) {
334 		rte_pci_add_device(dev);
335 	} else {
336 		struct rte_pci_device *dev2;
337 		int ret;
338 
339 		TAILQ_FOREACH(dev2, &rte_pci_bus.device_list, next) {
340 			ret = rte_pci_addr_cmp(&dev->addr, &dev2->addr);
341 			if (ret > 0)
342 				continue;
343 
344 			if (ret < 0) {
345 				rte_pci_insert_device(dev2, dev);
346 			} else { /* already registered */
347 				dev2->kdrv = dev->kdrv;
348 				dev2->max_vfs = dev->max_vfs;
349 				pci_name_set(dev2);
350 				memmove(dev2->mem_resource, dev->mem_resource,
351 					sizeof(dev->mem_resource));
352 				free(dev);
353 			}
354 			return 0;
355 		}
356 
357 		rte_pci_add_device(dev);
358 	}
359 
360 	return 0;
361 }
362 
363 int
364 pci_update_device(const struct rte_pci_addr *addr)
365 {
366 	char filename[PATH_MAX];
367 
368 	snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT,
369 		 rte_pci_get_sysfs_path(), addr->domain, addr->bus, addr->devid,
370 		 addr->function);
371 
372 	return pci_scan_one(filename, addr);
373 }
374 
375 /*
376  * split up a pci address into its constituent parts.
377  */
378 static int
379 parse_pci_addr_format(const char *buf, int bufsize, struct rte_pci_addr *addr)
380 {
381 	/* first split on ':' */
382 	union splitaddr {
383 		struct {
384 			char *domain;
385 			char *bus;
386 			char *devid;
387 			char *function;
388 		};
389 		char *str[PCI_FMT_NVAL]; /* last element-separator is "." not ":" */
390 	} splitaddr;
391 
392 	char *buf_copy = strndup(buf, bufsize);
393 	if (buf_copy == NULL)
394 		return -1;
395 
396 	if (rte_strsplit(buf_copy, bufsize, splitaddr.str, PCI_FMT_NVAL, ':')
397 			!= PCI_FMT_NVAL - 1)
398 		goto error;
399 	/* final split is on '.' between devid and function */
400 	splitaddr.function = strchr(splitaddr.devid,'.');
401 	if (splitaddr.function == NULL)
402 		goto error;
403 	*splitaddr.function++ = '\0';
404 
405 	/* now convert to int values */
406 	errno = 0;
407 	addr->domain = strtoul(splitaddr.domain, NULL, 16);
408 	addr->bus = strtoul(splitaddr.bus, NULL, 16);
409 	addr->devid = strtoul(splitaddr.devid, NULL, 16);
410 	addr->function = strtoul(splitaddr.function, NULL, 10);
411 	if (errno != 0)
412 		goto error;
413 
414 	free(buf_copy); /* free the copy made with strdup */
415 	return 0;
416 error:
417 	free(buf_copy);
418 	return -1;
419 }
420 
421 /*
422  * Scan the content of the PCI bus, and the devices in the devices
423  * list
424  */
425 int
426 rte_pci_scan(void)
427 {
428 	struct dirent *e;
429 	DIR *dir;
430 	char dirname[PATH_MAX];
431 	struct rte_pci_addr addr;
432 
433 	/* for debug purposes, PCI can be disabled */
434 	if (!rte_eal_has_pci())
435 		return 0;
436 
437 #ifdef VFIO_PRESENT
438 	if (!pci_vfio_is_enabled())
439 		RTE_LOG(DEBUG, EAL, "VFIO PCI modules not loaded\n");
440 #endif
441 
442 	dir = opendir(rte_pci_get_sysfs_path());
443 	if (dir == NULL) {
444 		RTE_LOG(ERR, EAL, "%s(): opendir failed: %s\n",
445 			__func__, strerror(errno));
446 		return -1;
447 	}
448 
449 	while ((e = readdir(dir)) != NULL) {
450 		if (e->d_name[0] == '.')
451 			continue;
452 
453 		if (parse_pci_addr_format(e->d_name, sizeof(e->d_name), &addr) != 0)
454 			continue;
455 
456 		snprintf(dirname, sizeof(dirname), "%s/%s",
457 				rte_pci_get_sysfs_path(), e->d_name);
458 
459 		if (pci_scan_one(dirname, &addr) < 0)
460 			goto error;
461 	}
462 	closedir(dir);
463 	return 0;
464 
465 error:
466 	closedir(dir);
467 	return -1;
468 }
469 
470 /*
471  * Is pci device bound to any kdrv
472  */
473 static inline int
474 pci_one_device_is_bound(void)
475 {
476 	struct rte_pci_device *dev = NULL;
477 	int ret = 0;
478 
479 	FOREACH_DEVICE_ON_PCIBUS(dev) {
480 		if (dev->kdrv == RTE_KDRV_UNKNOWN ||
481 		    dev->kdrv == RTE_KDRV_NONE) {
482 			continue;
483 		} else {
484 			ret = 1;
485 			break;
486 		}
487 	}
488 	return ret;
489 }
490 
491 /*
492  * Any one of the device bound to uio
493  */
494 static inline int
495 pci_one_device_bound_uio(void)
496 {
497 	struct rte_pci_device *dev = NULL;
498 	struct rte_devargs *devargs;
499 	int need_check;
500 
501 	FOREACH_DEVICE_ON_PCIBUS(dev) {
502 		devargs = dev->device.devargs;
503 
504 		need_check = 0;
505 		switch (rte_pci_bus.bus.conf.scan_mode) {
506 		case RTE_BUS_SCAN_WHITELIST:
507 			if (devargs && devargs->policy == RTE_DEV_WHITELISTED)
508 				need_check = 1;
509 			break;
510 		case RTE_BUS_SCAN_UNDEFINED:
511 		case RTE_BUS_SCAN_BLACKLIST:
512 			if (devargs == NULL ||
513 			    devargs->policy != RTE_DEV_BLACKLISTED)
514 				need_check = 1;
515 			break;
516 		}
517 
518 		if (!need_check)
519 			continue;
520 
521 		if (dev->kdrv == RTE_KDRV_IGB_UIO ||
522 		   dev->kdrv == RTE_KDRV_UIO_GENERIC) {
523 			return 1;
524 		}
525 	}
526 	return 0;
527 }
528 
529 /*
530  * Any one of the device has iova as va
531  */
532 static inline int
533 pci_one_device_has_iova_va(void)
534 {
535 	struct rte_pci_device *dev = NULL;
536 	struct rte_pci_driver *drv = NULL;
537 
538 	FOREACH_DRIVER_ON_PCIBUS(drv) {
539 		if (drv && drv->drv_flags & RTE_PCI_DRV_IOVA_AS_VA) {
540 			FOREACH_DEVICE_ON_PCIBUS(dev) {
541 				if (dev->kdrv == RTE_KDRV_VFIO &&
542 				    rte_pci_match(drv, dev))
543 					return 1;
544 			}
545 		}
546 	}
547 	return 0;
548 }
549 
550 #if defined(RTE_ARCH_X86)
551 static bool
552 pci_one_device_iommu_support_va(struct rte_pci_device *dev)
553 {
554 #define VTD_CAP_MGAW_SHIFT	16
555 #define VTD_CAP_MGAW_MASK	(0x3fULL << VTD_CAP_MGAW_SHIFT)
556 #define X86_VA_WIDTH 47 /* From Documentation/x86/x86_64/mm.txt */
557 	struct rte_pci_addr *addr = &dev->addr;
558 	char filename[PATH_MAX];
559 	FILE *fp;
560 	uint64_t mgaw, vtd_cap_reg = 0;
561 
562 	snprintf(filename, sizeof(filename),
563 		 "%s/" PCI_PRI_FMT "/iommu/intel-iommu/cap",
564 		 rte_pci_get_sysfs_path(), addr->domain, addr->bus, addr->devid,
565 		 addr->function);
566 	if (access(filename, F_OK) == -1) {
567 		/* We don't have an Intel IOMMU, assume VA supported*/
568 		return true;
569 	}
570 
571 	/* We have an intel IOMMU */
572 	fp = fopen(filename, "r");
573 	if (fp == NULL) {
574 		RTE_LOG(ERR, EAL, "%s(): can't open %s\n", __func__, filename);
575 		return false;
576 	}
577 
578 	if (fscanf(fp, "%" PRIx64, &vtd_cap_reg) != 1) {
579 		RTE_LOG(ERR, EAL, "%s(): can't read %s\n", __func__, filename);
580 		fclose(fp);
581 		return false;
582 	}
583 
584 	fclose(fp);
585 
586 	mgaw = ((vtd_cap_reg & VTD_CAP_MGAW_MASK) >> VTD_CAP_MGAW_SHIFT) + 1;
587 	if (mgaw < X86_VA_WIDTH)
588 		return false;
589 
590 	return true;
591 }
592 #elif defined(RTE_ARCH_PPC_64)
593 static bool
594 pci_one_device_iommu_support_va(__rte_unused struct rte_pci_device *dev)
595 {
596 	return false;
597 }
598 #else
599 static bool
600 pci_one_device_iommu_support_va(__rte_unused struct rte_pci_device *dev)
601 {
602 	return true;
603 }
604 #endif
605 
606 /*
607  * All devices IOMMUs support VA as IOVA
608  */
609 static bool
610 pci_devices_iommu_support_va(void)
611 {
612 	struct rte_pci_device *dev = NULL;
613 	struct rte_pci_driver *drv = NULL;
614 
615 	FOREACH_DRIVER_ON_PCIBUS(drv) {
616 		FOREACH_DEVICE_ON_PCIBUS(dev) {
617 			if (!rte_pci_match(drv, dev))
618 				continue;
619 			if (!pci_one_device_iommu_support_va(dev))
620 				return false;
621 		}
622 	}
623 	return true;
624 }
625 
626 /*
627  * Get iommu class of PCI devices on the bus.
628  */
629 enum rte_iova_mode
630 rte_pci_get_iommu_class(void)
631 {
632 	bool is_bound;
633 	bool is_vfio_noiommu_enabled = true;
634 	bool has_iova_va;
635 	bool is_bound_uio;
636 	bool iommu_no_va;
637 
638 	is_bound = pci_one_device_is_bound();
639 	if (!is_bound)
640 		return RTE_IOVA_DC;
641 
642 	has_iova_va = pci_one_device_has_iova_va();
643 	is_bound_uio = pci_one_device_bound_uio();
644 	iommu_no_va = !pci_devices_iommu_support_va();
645 #ifdef VFIO_PRESENT
646 	is_vfio_noiommu_enabled = rte_vfio_noiommu_is_enabled() == true ?
647 					true : false;
648 #endif
649 
650 	if (has_iova_va && !is_bound_uio && !is_vfio_noiommu_enabled &&
651 			!iommu_no_va)
652 		return RTE_IOVA_VA;
653 
654 	if (has_iova_va) {
655 		RTE_LOG(WARNING, EAL, "Some devices want iova as va but pa will be used because.. ");
656 		if (is_vfio_noiommu_enabled)
657 			RTE_LOG(WARNING, EAL, "vfio-noiommu mode configured\n");
658 		if (is_bound_uio)
659 			RTE_LOG(WARNING, EAL, "few device bound to UIO\n");
660 		if (iommu_no_va)
661 			RTE_LOG(WARNING, EAL, "IOMMU does not support IOVA as VA\n");
662 	}
663 
664 	return RTE_IOVA_PA;
665 }
666 
667 /* Read PCI config space. */
668 int rte_pci_read_config(const struct rte_pci_device *device,
669 		void *buf, size_t len, off_t offset)
670 {
671 	const struct rte_intr_handle *intr_handle = &device->intr_handle;
672 
673 	switch (intr_handle->type) {
674 	case RTE_INTR_HANDLE_UIO:
675 	case RTE_INTR_HANDLE_UIO_INTX:
676 		return pci_uio_read_config(intr_handle, buf, len, offset);
677 
678 #ifdef VFIO_PRESENT
679 	case RTE_INTR_HANDLE_VFIO_MSIX:
680 	case RTE_INTR_HANDLE_VFIO_MSI:
681 	case RTE_INTR_HANDLE_VFIO_LEGACY:
682 		return pci_vfio_read_config(intr_handle, buf, len, offset);
683 #endif
684 	default:
685 		RTE_LOG(ERR, EAL,
686 			"Unknown handle type of fd %d\n",
687 					intr_handle->fd);
688 		return -1;
689 	}
690 }
691 
692 /* Write PCI config space. */
693 int rte_pci_write_config(const struct rte_pci_device *device,
694 		const void *buf, size_t len, off_t offset)
695 {
696 	const struct rte_intr_handle *intr_handle = &device->intr_handle;
697 
698 	switch (intr_handle->type) {
699 	case RTE_INTR_HANDLE_UIO:
700 	case RTE_INTR_HANDLE_UIO_INTX:
701 		return pci_uio_write_config(intr_handle, buf, len, offset);
702 
703 #ifdef VFIO_PRESENT
704 	case RTE_INTR_HANDLE_VFIO_MSIX:
705 	case RTE_INTR_HANDLE_VFIO_MSI:
706 	case RTE_INTR_HANDLE_VFIO_LEGACY:
707 		return pci_vfio_write_config(intr_handle, buf, len, offset);
708 #endif
709 	default:
710 		RTE_LOG(ERR, EAL,
711 			"Unknown handle type of fd %d\n",
712 					intr_handle->fd);
713 		return -1;
714 	}
715 }
716 
717 #if defined(RTE_ARCH_X86)
718 static int
719 pci_ioport_map(struct rte_pci_device *dev, int bar __rte_unused,
720 		struct rte_pci_ioport *p)
721 {
722 	uint16_t start, end;
723 	FILE *fp;
724 	char *line = NULL;
725 	char pci_id[16];
726 	int found = 0;
727 	size_t linesz;
728 
729 	snprintf(pci_id, sizeof(pci_id), PCI_PRI_FMT,
730 		 dev->addr.domain, dev->addr.bus,
731 		 dev->addr.devid, dev->addr.function);
732 
733 	fp = fopen("/proc/ioports", "r");
734 	if (fp == NULL) {
735 		RTE_LOG(ERR, EAL, "%s(): can't open ioports\n", __func__);
736 		return -1;
737 	}
738 
739 	while (getdelim(&line, &linesz, '\n', fp) > 0) {
740 		char *ptr = line;
741 		char *left;
742 		int n;
743 
744 		n = strcspn(ptr, ":");
745 		ptr[n] = 0;
746 		left = &ptr[n + 1];
747 
748 		while (*left && isspace(*left))
749 			left++;
750 
751 		if (!strncmp(left, pci_id, strlen(pci_id))) {
752 			found = 1;
753 
754 			while (*ptr && isspace(*ptr))
755 				ptr++;
756 
757 			sscanf(ptr, "%04hx-%04hx", &start, &end);
758 
759 			break;
760 		}
761 	}
762 
763 	free(line);
764 	fclose(fp);
765 
766 	if (!found)
767 		return -1;
768 
769 	p->base = start;
770 	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%x\n", start);
771 
772 	return 0;
773 }
774 #endif
775 
776 int
777 rte_pci_ioport_map(struct rte_pci_device *dev, int bar,
778 		struct rte_pci_ioport *p)
779 {
780 	int ret = -1;
781 
782 	switch (dev->kdrv) {
783 #ifdef VFIO_PRESENT
784 	case RTE_KDRV_VFIO:
785 		if (pci_vfio_is_enabled())
786 			ret = pci_vfio_ioport_map(dev, bar, p);
787 		break;
788 #endif
789 	case RTE_KDRV_IGB_UIO:
790 		ret = pci_uio_ioport_map(dev, bar, p);
791 		break;
792 	case RTE_KDRV_UIO_GENERIC:
793 #if defined(RTE_ARCH_X86)
794 		ret = pci_ioport_map(dev, bar, p);
795 #else
796 		ret = pci_uio_ioport_map(dev, bar, p);
797 #endif
798 		break;
799 	case RTE_KDRV_NONE:
800 #if defined(RTE_ARCH_X86)
801 		ret = pci_ioport_map(dev, bar, p);
802 #endif
803 		break;
804 	default:
805 		break;
806 	}
807 
808 	if (!ret)
809 		p->dev = dev;
810 
811 	return ret;
812 }
813 
814 void
815 rte_pci_ioport_read(struct rte_pci_ioport *p,
816 		void *data, size_t len, off_t offset)
817 {
818 	switch (p->dev->kdrv) {
819 #ifdef VFIO_PRESENT
820 	case RTE_KDRV_VFIO:
821 		pci_vfio_ioport_read(p, data, len, offset);
822 		break;
823 #endif
824 	case RTE_KDRV_IGB_UIO:
825 		pci_uio_ioport_read(p, data, len, offset);
826 		break;
827 	case RTE_KDRV_UIO_GENERIC:
828 		pci_uio_ioport_read(p, data, len, offset);
829 		break;
830 	case RTE_KDRV_NONE:
831 #if defined(RTE_ARCH_X86)
832 		pci_uio_ioport_read(p, data, len, offset);
833 #endif
834 		break;
835 	default:
836 		break;
837 	}
838 }
839 
840 void
841 rte_pci_ioport_write(struct rte_pci_ioport *p,
842 		const void *data, size_t len, off_t offset)
843 {
844 	switch (p->dev->kdrv) {
845 #ifdef VFIO_PRESENT
846 	case RTE_KDRV_VFIO:
847 		pci_vfio_ioport_write(p, data, len, offset);
848 		break;
849 #endif
850 	case RTE_KDRV_IGB_UIO:
851 		pci_uio_ioport_write(p, data, len, offset);
852 		break;
853 	case RTE_KDRV_UIO_GENERIC:
854 		pci_uio_ioport_write(p, data, len, offset);
855 		break;
856 	case RTE_KDRV_NONE:
857 #if defined(RTE_ARCH_X86)
858 		pci_uio_ioport_write(p, data, len, offset);
859 #endif
860 		break;
861 	default:
862 		break;
863 	}
864 }
865 
866 int
867 rte_pci_ioport_unmap(struct rte_pci_ioport *p)
868 {
869 	int ret = -1;
870 
871 	switch (p->dev->kdrv) {
872 #ifdef VFIO_PRESENT
873 	case RTE_KDRV_VFIO:
874 		if (pci_vfio_is_enabled())
875 			ret = pci_vfio_ioport_unmap(p);
876 		break;
877 #endif
878 	case RTE_KDRV_IGB_UIO:
879 		ret = pci_uio_ioport_unmap(p);
880 		break;
881 	case RTE_KDRV_UIO_GENERIC:
882 #if defined(RTE_ARCH_X86)
883 		ret = 0;
884 #else
885 		ret = pci_uio_ioport_unmap(p);
886 #endif
887 		break;
888 	case RTE_KDRV_NONE:
889 #if defined(RTE_ARCH_X86)
890 		ret = 0;
891 #endif
892 		break;
893 	default:
894 		break;
895 	}
896 
897 	return ret;
898 }
899