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