xref: /dpdk/drivers/bus/pci/linux/pci_uio.c (revision 46dcbccd3a2715fb2059c51544722aabd2fe40f7)
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 <unistd.h>
7c752998bSGaetan Rivet #include <fcntl.h>
8c752998bSGaetan Rivet #include <dirent.h>
9c752998bSGaetan Rivet #include <inttypes.h>
10c752998bSGaetan Rivet #include <sys/stat.h>
11c752998bSGaetan Rivet #include <sys/mman.h>
12c752998bSGaetan Rivet #include <sys/sysmacros.h>
13c752998bSGaetan Rivet #include <linux/pci_regs.h>
14c752998bSGaetan Rivet 
15c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
16c752998bSGaetan Rivet #include <sys/io.h>
17c752998bSGaetan Rivet #endif
18c752998bSGaetan Rivet 
196723c0fcSBruce Richardson #include <rte_string_fns.h>
20c752998bSGaetan Rivet #include <rte_log.h>
21c752998bSGaetan Rivet #include <rte_pci.h>
22c752998bSGaetan Rivet #include <rte_bus_pci.h>
23c752998bSGaetan Rivet #include <rte_common.h>
24c752998bSGaetan Rivet #include <rte_malloc.h>
25c752998bSGaetan Rivet 
26c752998bSGaetan Rivet #include "eal_filesystem.h"
27c752998bSGaetan Rivet #include "pci_init.h"
28e1ece609SDavid Marchand #include "private.h"
29c752998bSGaetan Rivet 
30c752998bSGaetan Rivet void *pci_map_addr = NULL;
31c752998bSGaetan Rivet 
32c752998bSGaetan Rivet #define OFF_MAX              ((uint64_t)(off_t)-1)
33c752998bSGaetan Rivet 
34c752998bSGaetan Rivet int
35c752998bSGaetan Rivet pci_uio_read_config(const struct rte_intr_handle *intr_handle,
36c752998bSGaetan Rivet 		    void *buf, size_t len, off_t offset)
37c752998bSGaetan Rivet {
38c752998bSGaetan Rivet 	return pread(intr_handle->uio_cfg_fd, buf, len, offset);
39c752998bSGaetan Rivet }
40c752998bSGaetan Rivet 
41c752998bSGaetan Rivet int
42c752998bSGaetan Rivet pci_uio_write_config(const struct rte_intr_handle *intr_handle,
43c752998bSGaetan Rivet 		     const void *buf, size_t len, off_t offset)
44c752998bSGaetan Rivet {
45c752998bSGaetan Rivet 	return pwrite(intr_handle->uio_cfg_fd, buf, len, offset);
46c752998bSGaetan Rivet }
47c752998bSGaetan Rivet 
48c752998bSGaetan Rivet static int
49c752998bSGaetan Rivet pci_uio_set_bus_master(int dev_fd)
50c752998bSGaetan Rivet {
51c752998bSGaetan Rivet 	uint16_t reg;
52c752998bSGaetan Rivet 	int ret;
53c752998bSGaetan Rivet 
54c752998bSGaetan Rivet 	ret = pread(dev_fd, &reg, sizeof(reg), PCI_COMMAND);
55c752998bSGaetan Rivet 	if (ret != sizeof(reg)) {
56c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL,
57c752998bSGaetan Rivet 			"Cannot read command from PCI config space!\n");
58c752998bSGaetan Rivet 		return -1;
59c752998bSGaetan Rivet 	}
60c752998bSGaetan Rivet 
61c752998bSGaetan Rivet 	/* return if bus mastering is already on */
62c752998bSGaetan Rivet 	if (reg & PCI_COMMAND_MASTER)
63c752998bSGaetan Rivet 		return 0;
64c752998bSGaetan Rivet 
65c752998bSGaetan Rivet 	reg |= PCI_COMMAND_MASTER;
66c752998bSGaetan Rivet 
67c752998bSGaetan Rivet 	ret = pwrite(dev_fd, &reg, sizeof(reg), PCI_COMMAND);
68c752998bSGaetan Rivet 	if (ret != sizeof(reg)) {
69c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL,
70c752998bSGaetan Rivet 			"Cannot write command to PCI config space!\n");
71c752998bSGaetan Rivet 		return -1;
72c752998bSGaetan Rivet 	}
73c752998bSGaetan Rivet 
74c752998bSGaetan Rivet 	return 0;
75c752998bSGaetan Rivet }
76c752998bSGaetan Rivet 
77c752998bSGaetan Rivet static int
78c752998bSGaetan Rivet pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num)
79c752998bSGaetan Rivet {
80c752998bSGaetan Rivet 	FILE *f;
81c752998bSGaetan Rivet 	char filename[PATH_MAX];
82c752998bSGaetan Rivet 	int ret;
83c752998bSGaetan Rivet 	unsigned major, minor;
84c752998bSGaetan Rivet 	dev_t dev;
85c752998bSGaetan Rivet 
86c752998bSGaetan Rivet 	/* get the name of the sysfs file that contains the major and minor
87c752998bSGaetan Rivet 	 * of the uio device and read its content */
88c752998bSGaetan Rivet 	snprintf(filename, sizeof(filename), "%s/dev", sysfs_uio_path);
89c752998bSGaetan Rivet 
90c752998bSGaetan Rivet 	f = fopen(filename, "r");
91c752998bSGaetan Rivet 	if (f == NULL) {
92c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "%s(): cannot open sysfs to get major:minor\n",
93c752998bSGaetan Rivet 			__func__);
94c752998bSGaetan Rivet 		return -1;
95c752998bSGaetan Rivet 	}
96c752998bSGaetan Rivet 
97c752998bSGaetan Rivet 	ret = fscanf(f, "%u:%u", &major, &minor);
98c752998bSGaetan Rivet 	if (ret != 2) {
99c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "%s(): cannot parse sysfs to get major:minor\n",
100c752998bSGaetan Rivet 			__func__);
101c752998bSGaetan Rivet 		fclose(f);
102c752998bSGaetan Rivet 		return -1;
103c752998bSGaetan Rivet 	}
104c752998bSGaetan Rivet 	fclose(f);
105c752998bSGaetan Rivet 
106c752998bSGaetan Rivet 	/* create the char device "mknod /dev/uioX c major minor" */
107c752998bSGaetan Rivet 	snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num);
108c752998bSGaetan Rivet 	dev = makedev(major, minor);
109c752998bSGaetan Rivet 	ret = mknod(filename, S_IFCHR | S_IRUSR | S_IWUSR, dev);
110c752998bSGaetan Rivet 	if (ret != 0) {
111c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "%s(): mknod() failed %s\n",
112c752998bSGaetan Rivet 			__func__, strerror(errno));
113c752998bSGaetan Rivet 		return -1;
114c752998bSGaetan Rivet 	}
115c752998bSGaetan Rivet 
116c752998bSGaetan Rivet 	return ret;
117c752998bSGaetan Rivet }
118c752998bSGaetan Rivet 
119c752998bSGaetan Rivet /*
120c752998bSGaetan Rivet  * Return the uioX char device used for a pci device. On success, return
121c752998bSGaetan Rivet  * the UIO number and fill dstbuf string with the path of the device in
122c752998bSGaetan Rivet  * sysfs. On error, return a negative value. In this case dstbuf is
123c752998bSGaetan Rivet  * invalid.
124c752998bSGaetan Rivet  */
125c752998bSGaetan Rivet static int
126c752998bSGaetan Rivet pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
127c752998bSGaetan Rivet 			   unsigned int buflen, int create)
128c752998bSGaetan Rivet {
129c752998bSGaetan Rivet 	struct rte_pci_addr *loc = &dev->addr;
130c752998bSGaetan Rivet 	int uio_num = -1;
131c752998bSGaetan Rivet 	struct dirent *e;
132c752998bSGaetan Rivet 	DIR *dir;
133c752998bSGaetan Rivet 	char dirname[PATH_MAX];
134c752998bSGaetan Rivet 
135c752998bSGaetan Rivet 	/* depending on kernel version, uio can be located in uio/uioX
136c752998bSGaetan Rivet 	 * or uio:uioX */
137c752998bSGaetan Rivet 
138c752998bSGaetan Rivet 	snprintf(dirname, sizeof(dirname),
139c52dd394SThomas Monjalon 			"%s/" PCI_PRI_FMT "/uio", rte_pci_get_sysfs_path(),
140c752998bSGaetan Rivet 			loc->domain, loc->bus, loc->devid, loc->function);
141c752998bSGaetan Rivet 
142c752998bSGaetan Rivet 	dir = opendir(dirname);
143c752998bSGaetan Rivet 	if (dir == NULL) {
144c752998bSGaetan Rivet 		/* retry with the parent directory */
145c752998bSGaetan Rivet 		snprintf(dirname, sizeof(dirname),
146c52dd394SThomas Monjalon 				"%s/" PCI_PRI_FMT, rte_pci_get_sysfs_path(),
147c752998bSGaetan Rivet 				loc->domain, loc->bus, loc->devid, loc->function);
148c752998bSGaetan Rivet 		dir = opendir(dirname);
149c752998bSGaetan Rivet 
150c752998bSGaetan Rivet 		if (dir == NULL) {
151c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "Cannot opendir %s\n", dirname);
152c752998bSGaetan Rivet 			return -1;
153c752998bSGaetan Rivet 		}
154c752998bSGaetan Rivet 	}
155c752998bSGaetan Rivet 
156c752998bSGaetan Rivet 	/* take the first file starting with "uio" */
157c752998bSGaetan Rivet 	while ((e = readdir(dir)) != NULL) {
158c752998bSGaetan Rivet 		/* format could be uio%d ...*/
159c752998bSGaetan Rivet 		int shortprefix_len = sizeof("uio") - 1;
160c752998bSGaetan Rivet 		/* ... or uio:uio%d */
161c752998bSGaetan Rivet 		int longprefix_len = sizeof("uio:uio") - 1;
162c752998bSGaetan Rivet 		char *endptr;
163c752998bSGaetan Rivet 
164c752998bSGaetan Rivet 		if (strncmp(e->d_name, "uio", 3) != 0)
165c752998bSGaetan Rivet 			continue;
166c752998bSGaetan Rivet 
167c752998bSGaetan Rivet 		/* first try uio%d */
168c752998bSGaetan Rivet 		errno = 0;
169c752998bSGaetan Rivet 		uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10);
170c752998bSGaetan Rivet 		if (errno == 0 && endptr != (e->d_name + shortprefix_len)) {
171c752998bSGaetan Rivet 			snprintf(dstbuf, buflen, "%s/uio%u", dirname, uio_num);
172c752998bSGaetan Rivet 			break;
173c752998bSGaetan Rivet 		}
174c752998bSGaetan Rivet 
175c752998bSGaetan Rivet 		/* then try uio:uio%d */
176c752998bSGaetan Rivet 		errno = 0;
177c752998bSGaetan Rivet 		uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10);
178c752998bSGaetan Rivet 		if (errno == 0 && endptr != (e->d_name + longprefix_len)) {
179c752998bSGaetan Rivet 			snprintf(dstbuf, buflen, "%s/uio:uio%u", dirname, uio_num);
180c752998bSGaetan Rivet 			break;
181c752998bSGaetan Rivet 		}
182c752998bSGaetan Rivet 	}
183c752998bSGaetan Rivet 	closedir(dir);
184c752998bSGaetan Rivet 
185c752998bSGaetan Rivet 	/* No uio resource found */
186c752998bSGaetan Rivet 	if (e == NULL)
187c752998bSGaetan Rivet 		return -1;
188c752998bSGaetan Rivet 
189c752998bSGaetan Rivet 	/* create uio device if we've been asked to */
190c752998bSGaetan Rivet 	if (rte_eal_create_uio_dev() && create &&
191c752998bSGaetan Rivet 			pci_mknod_uio_dev(dstbuf, uio_num) < 0)
192c752998bSGaetan Rivet 		RTE_LOG(WARNING, EAL, "Cannot create /dev/uio%u\n", uio_num);
193c752998bSGaetan Rivet 
194c752998bSGaetan Rivet 	return uio_num;
195c752998bSGaetan Rivet }
196c752998bSGaetan Rivet 
197c752998bSGaetan Rivet void
198c752998bSGaetan Rivet pci_uio_free_resource(struct rte_pci_device *dev,
199c752998bSGaetan Rivet 		struct mapped_pci_resource *uio_res)
200c752998bSGaetan Rivet {
201c752998bSGaetan Rivet 	rte_free(uio_res);
202c752998bSGaetan Rivet 
203c752998bSGaetan Rivet 	if (dev->intr_handle.uio_cfg_fd >= 0) {
204c752998bSGaetan Rivet 		close(dev->intr_handle.uio_cfg_fd);
205c752998bSGaetan Rivet 		dev->intr_handle.uio_cfg_fd = -1;
206c752998bSGaetan Rivet 	}
207c752998bSGaetan Rivet 	if (dev->intr_handle.fd >= 0) {
208c752998bSGaetan Rivet 		close(dev->intr_handle.fd);
209c752998bSGaetan Rivet 		dev->intr_handle.fd = -1;
210c752998bSGaetan Rivet 		dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN;
211c752998bSGaetan Rivet 	}
212c752998bSGaetan Rivet }
213c752998bSGaetan Rivet 
214c752998bSGaetan Rivet int
215c752998bSGaetan Rivet pci_uio_alloc_resource(struct rte_pci_device *dev,
216c752998bSGaetan Rivet 		struct mapped_pci_resource **uio_res)
217c752998bSGaetan Rivet {
218c752998bSGaetan Rivet 	char dirname[PATH_MAX];
219c752998bSGaetan Rivet 	char cfgname[PATH_MAX];
220c752998bSGaetan Rivet 	char devname[PATH_MAX]; /* contains the /dev/uioX */
221c752998bSGaetan Rivet 	int uio_num;
222c752998bSGaetan Rivet 	struct rte_pci_addr *loc;
223c752998bSGaetan Rivet 
224c752998bSGaetan Rivet 	loc = &dev->addr;
225c752998bSGaetan Rivet 
226c752998bSGaetan Rivet 	/* find uio resource */
227c752998bSGaetan Rivet 	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 1);
228c752998bSGaetan Rivet 	if (uio_num < 0) {
229c752998bSGaetan Rivet 		RTE_LOG(WARNING, EAL, "  "PCI_PRI_FMT" not managed by UIO driver, "
230c752998bSGaetan Rivet 				"skipping\n", loc->domain, loc->bus, loc->devid, loc->function);
231c752998bSGaetan Rivet 		return 1;
232c752998bSGaetan Rivet 	}
233c752998bSGaetan Rivet 	snprintf(devname, sizeof(devname), "/dev/uio%u", uio_num);
234c752998bSGaetan Rivet 
235c752998bSGaetan Rivet 	/* save fd if in primary process */
236c752998bSGaetan Rivet 	dev->intr_handle.fd = open(devname, O_RDWR);
237c752998bSGaetan Rivet 	if (dev->intr_handle.fd < 0) {
238c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
239c752998bSGaetan Rivet 			devname, strerror(errno));
240c752998bSGaetan Rivet 		goto error;
241c752998bSGaetan Rivet 	}
242c752998bSGaetan Rivet 
243c752998bSGaetan Rivet 	snprintf(cfgname, sizeof(cfgname),
244c752998bSGaetan Rivet 			"/sys/class/uio/uio%u/device/config", uio_num);
245c752998bSGaetan Rivet 	dev->intr_handle.uio_cfg_fd = open(cfgname, O_RDWR);
246c752998bSGaetan Rivet 	if (dev->intr_handle.uio_cfg_fd < 0) {
247c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
248c752998bSGaetan Rivet 			cfgname, strerror(errno));
249c752998bSGaetan Rivet 		goto error;
250c752998bSGaetan Rivet 	}
251c752998bSGaetan Rivet 
2527c0d798aSDavid Marchand 	if (dev->kdrv == RTE_PCI_KDRV_IGB_UIO)
253c752998bSGaetan Rivet 		dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
254c752998bSGaetan Rivet 	else {
255c752998bSGaetan Rivet 		dev->intr_handle.type = RTE_INTR_HANDLE_UIO_INTX;
256c752998bSGaetan Rivet 
257c752998bSGaetan Rivet 		/* set bus master that is not done by uio_pci_generic */
258c752998bSGaetan Rivet 		if (pci_uio_set_bus_master(dev->intr_handle.uio_cfg_fd)) {
259c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "Cannot set up bus mastering!\n");
260c752998bSGaetan Rivet 			goto error;
261c752998bSGaetan Rivet 		}
262c752998bSGaetan Rivet 	}
263c752998bSGaetan Rivet 
264c752998bSGaetan Rivet 	/* allocate the mapping details for secondary processes*/
265c752998bSGaetan Rivet 	*uio_res = rte_zmalloc("UIO_RES", sizeof(**uio_res), 0);
266c752998bSGaetan Rivet 	if (*uio_res == NULL) {
267c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL,
268c752998bSGaetan Rivet 			"%s(): cannot store uio mmap details\n", __func__);
269c752998bSGaetan Rivet 		goto error;
270c752998bSGaetan Rivet 	}
271c752998bSGaetan Rivet 
2726723c0fcSBruce Richardson 	strlcpy((*uio_res)->path, devname, sizeof((*uio_res)->path));
273c752998bSGaetan Rivet 	memcpy(&(*uio_res)->pci_addr, &dev->addr, sizeof((*uio_res)->pci_addr));
274c752998bSGaetan Rivet 
275c752998bSGaetan Rivet 	return 0;
276c752998bSGaetan Rivet 
277c752998bSGaetan Rivet error:
278c752998bSGaetan Rivet 	pci_uio_free_resource(dev, *uio_res);
279c752998bSGaetan Rivet 	return -1;
280c752998bSGaetan Rivet }
281c752998bSGaetan Rivet 
282c752998bSGaetan Rivet int
283c752998bSGaetan Rivet pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,
284c752998bSGaetan Rivet 		struct mapped_pci_resource *uio_res, int map_idx)
285c752998bSGaetan Rivet {
2864a928ef9SRafal Kozik 	int fd = -1;
287c752998bSGaetan Rivet 	char devname[PATH_MAX];
288c752998bSGaetan Rivet 	void *mapaddr;
289c752998bSGaetan Rivet 	struct rte_pci_addr *loc;
290c752998bSGaetan Rivet 	struct pci_map *maps;
2914a928ef9SRafal Kozik 	int wc_activate = 0;
2924a928ef9SRafal Kozik 
2934a928ef9SRafal Kozik 	if (dev->driver != NULL)
2944a928ef9SRafal Kozik 		wc_activate = dev->driver->drv_flags & RTE_PCI_DRV_WC_ACTIVATE;
295c752998bSGaetan Rivet 
296c752998bSGaetan Rivet 	loc = &dev->addr;
297c752998bSGaetan Rivet 	maps = uio_res->maps;
298c752998bSGaetan Rivet 
299c752998bSGaetan Rivet 	/* allocate memory to keep path */
300d3110b12SFerruh Yigit 	maps[map_idx].path = rte_malloc(NULL, sizeof(devname), 0);
301c752998bSGaetan Rivet 	if (maps[map_idx].path == NULL) {
302c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot allocate memory for path: %s\n",
303c752998bSGaetan Rivet 				strerror(errno));
304c752998bSGaetan Rivet 		return -1;
305c752998bSGaetan Rivet 	}
306c752998bSGaetan Rivet 
307c752998bSGaetan Rivet 	/*
308c752998bSGaetan Rivet 	 * open resource file, to mmap it
309c752998bSGaetan Rivet 	 */
3104a928ef9SRafal Kozik 	if (wc_activate) {
3114a928ef9SRafal Kozik 		/* update devname for mmap  */
3124a928ef9SRafal Kozik 		snprintf(devname, sizeof(devname),
3134a928ef9SRafal Kozik 			"%s/" PCI_PRI_FMT "/resource%d_wc",
3144a928ef9SRafal Kozik 			rte_pci_get_sysfs_path(),
3154a928ef9SRafal Kozik 			loc->domain, loc->bus, loc->devid,
3164a928ef9SRafal Kozik 			loc->function, res_idx);
3174a928ef9SRafal Kozik 
3184a928ef9SRafal Kozik 		fd = open(devname, O_RDWR);
319c530aa78SStephen Hemminger 		if (fd < 0 && errno != ENOENT) {
3204a928ef9SRafal Kozik 			RTE_LOG(INFO, EAL, "%s cannot be mapped. "
3214a928ef9SRafal Kozik 				"Fall-back to non prefetchable mode.\n",
3224a928ef9SRafal Kozik 				devname);
3234a928ef9SRafal Kozik 		}
3244a928ef9SRafal Kozik 	}
3254a928ef9SRafal Kozik 
3264a928ef9SRafal Kozik 	if (!wc_activate || fd < 0) {
3274a928ef9SRafal Kozik 		snprintf(devname, sizeof(devname),
3284a928ef9SRafal Kozik 			"%s/" PCI_PRI_FMT "/resource%d",
3294a928ef9SRafal Kozik 			rte_pci_get_sysfs_path(),
3304a928ef9SRafal Kozik 			loc->domain, loc->bus, loc->devid,
3314a928ef9SRafal Kozik 			loc->function, res_idx);
3324a928ef9SRafal Kozik 
3334a928ef9SRafal Kozik 		/* then try to map resource file */
334c752998bSGaetan Rivet 		fd = open(devname, O_RDWR);
335c752998bSGaetan Rivet 		if (fd < 0) {
336c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
337c752998bSGaetan Rivet 				devname, strerror(errno));
338c752998bSGaetan Rivet 			goto error;
339c752998bSGaetan Rivet 		}
3404a928ef9SRafal Kozik 	}
341c752998bSGaetan Rivet 
342c752998bSGaetan Rivet 	/* try mapping somewhere close to the end of hugepages */
343c752998bSGaetan Rivet 	if (pci_map_addr == NULL)
344c752998bSGaetan Rivet 		pci_map_addr = pci_find_max_end_va();
345c752998bSGaetan Rivet 
346c752998bSGaetan Rivet 	mapaddr = pci_map_resource(pci_map_addr, fd, 0,
347c752998bSGaetan Rivet 			(size_t)dev->mem_resource[res_idx].len, 0);
348c752998bSGaetan Rivet 	close(fd);
349e200535cSDavid Marchand 	if (mapaddr == NULL)
350c752998bSGaetan Rivet 		goto error;
351c752998bSGaetan Rivet 
352c752998bSGaetan Rivet 	pci_map_addr = RTE_PTR_ADD(mapaddr,
353c752998bSGaetan Rivet 			(size_t)dev->mem_resource[res_idx].len);
354c752998bSGaetan Rivet 
355d25ab4b7SWangyu (Eric) 	pci_map_addr = RTE_PTR_ALIGN(pci_map_addr, sysconf(_SC_PAGE_SIZE));
356d25ab4b7SWangyu (Eric) 
357c752998bSGaetan Rivet 	maps[map_idx].phaddr = dev->mem_resource[res_idx].phys_addr;
358c752998bSGaetan Rivet 	maps[map_idx].size = dev->mem_resource[res_idx].len;
359c752998bSGaetan Rivet 	maps[map_idx].addr = mapaddr;
360c752998bSGaetan Rivet 	maps[map_idx].offset = 0;
361c752998bSGaetan Rivet 	strcpy(maps[map_idx].path, devname);
362c752998bSGaetan Rivet 	dev->mem_resource[res_idx].addr = mapaddr;
363c752998bSGaetan Rivet 
364c752998bSGaetan Rivet 	return 0;
365c752998bSGaetan Rivet 
366c752998bSGaetan Rivet error:
367c752998bSGaetan Rivet 	rte_free(maps[map_idx].path);
368c752998bSGaetan Rivet 	return -1;
369c752998bSGaetan Rivet }
370c752998bSGaetan Rivet 
371c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
372c752998bSGaetan Rivet int
373c752998bSGaetan Rivet pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
374c752998bSGaetan Rivet 		   struct rte_pci_ioport *p)
375c752998bSGaetan Rivet {
376*46dcbccdSHuawei Xie 	FILE *f = NULL;
377c752998bSGaetan Rivet 	char dirname[PATH_MAX];
378c752998bSGaetan Rivet 	char filename[PATH_MAX];
379*46dcbccdSHuawei Xie 	char buf[BUFSIZ];
380*46dcbccdSHuawei Xie 	uint64_t phys_addr, end_addr, flags;
381*46dcbccdSHuawei Xie 	unsigned long base;
382*46dcbccdSHuawei Xie 	int i;
383c752998bSGaetan Rivet 
384e02b661bSDavid Marchand 	if (rte_eal_iopl_init() != 0) {
385e02b661bSDavid Marchand 		RTE_LOG(ERR, EAL, "%s(): insufficient ioport permissions for PCI device %s\n",
386e02b661bSDavid Marchand 			__func__, dev->name);
387e02b661bSDavid Marchand 		return -1;
388e02b661bSDavid Marchand 	}
389e02b661bSDavid Marchand 
390*46dcbccdSHuawei Xie 	/* open and read addresses of the corresponding resource in sysfs */
391*46dcbccdSHuawei Xie 	snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource",
392*46dcbccdSHuawei Xie 		rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
393*46dcbccdSHuawei Xie 		dev->addr.devid, dev->addr.function);
394*46dcbccdSHuawei Xie 	f = fopen(filename, "r");
395*46dcbccdSHuawei Xie 	if (f == NULL) {
396*46dcbccdSHuawei Xie 		RTE_LOG(ERR, EAL, "%s(): Cannot open sysfs resource: %s\n",
397*46dcbccdSHuawei Xie 			__func__, strerror(errno));
398c752998bSGaetan Rivet 		return -1;
399c752998bSGaetan Rivet 	}
400*46dcbccdSHuawei Xie 
401*46dcbccdSHuawei Xie 	for (i = 0; i < bar + 1; i++) {
402*46dcbccdSHuawei Xie 		if (fgets(buf, sizeof(buf), f) == NULL) {
403*46dcbccdSHuawei Xie 			RTE_LOG(ERR, EAL, "%s(): Cannot read sysfs resource\n", __func__);
404*46dcbccdSHuawei Xie 			goto error;
405*46dcbccdSHuawei Xie 		}
406*46dcbccdSHuawei Xie 	}
407*46dcbccdSHuawei Xie 	if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr,
408*46dcbccdSHuawei Xie 		&end_addr, &flags) < 0)
409*46dcbccdSHuawei Xie 		goto error;
410*46dcbccdSHuawei Xie 
411*46dcbccdSHuawei Xie 	if (!(flags & IORESOURCE_IO)) {
412*46dcbccdSHuawei Xie 		RTE_LOG(ERR, EAL, "%s(): bar resource other than IO is not supported\n", __func__);
413*46dcbccdSHuawei Xie 		goto error;
414*46dcbccdSHuawei Xie 	}
415*46dcbccdSHuawei Xie 	base = (unsigned long)phys_addr;
416*46dcbccdSHuawei Xie 	RTE_LOG(INFO, EAL, "%s(): PIO BAR %08lx detected\n", __func__, base);
417*46dcbccdSHuawei Xie 
418*46dcbccdSHuawei Xie 	if (base > UINT16_MAX)
419*46dcbccdSHuawei Xie 		goto error;
420c752998bSGaetan Rivet 
421c752998bSGaetan Rivet 	/* FIXME only for primary process ? */
422c752998bSGaetan Rivet 	if (dev->intr_handle.type == RTE_INTR_HANDLE_UNKNOWN) {
423*46dcbccdSHuawei Xie 		int uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
424*46dcbccdSHuawei Xie 		if (uio_num < 0) {
425*46dcbccdSHuawei Xie 			RTE_LOG(ERR, EAL, "cannot open %s: %s\n",
426*46dcbccdSHuawei Xie 				dirname, strerror(errno));
427*46dcbccdSHuawei Xie 			goto error;
428*46dcbccdSHuawei Xie 		}
429c752998bSGaetan Rivet 
430c752998bSGaetan Rivet 		snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num);
431c752998bSGaetan Rivet 		dev->intr_handle.fd = open(filename, O_RDWR);
432c752998bSGaetan Rivet 		if (dev->intr_handle.fd < 0) {
433c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
434c752998bSGaetan Rivet 				filename, strerror(errno));
435*46dcbccdSHuawei Xie 			goto error;
436c752998bSGaetan Rivet 		}
437c752998bSGaetan Rivet 		dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
438c752998bSGaetan Rivet 	}
439c752998bSGaetan Rivet 
440*46dcbccdSHuawei Xie 	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%lx\n", base);
441c752998bSGaetan Rivet 
442*46dcbccdSHuawei Xie 	p->base = base;
443c752998bSGaetan Rivet 	p->len = 0;
444*46dcbccdSHuawei Xie 	fclose(f);
445c752998bSGaetan Rivet 	return 0;
446*46dcbccdSHuawei Xie error:
447*46dcbccdSHuawei Xie 	if (f)
448*46dcbccdSHuawei Xie 		fclose(f);
449*46dcbccdSHuawei Xie 	return -1;
450c752998bSGaetan Rivet }
451c752998bSGaetan Rivet #else
452c752998bSGaetan Rivet int
453c752998bSGaetan Rivet pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
454c752998bSGaetan Rivet 		   struct rte_pci_ioport *p)
455c752998bSGaetan Rivet {
456c752998bSGaetan Rivet 	FILE *f;
457c752998bSGaetan Rivet 	char buf[BUFSIZ];
458c752998bSGaetan Rivet 	char filename[PATH_MAX];
459c752998bSGaetan Rivet 	uint64_t phys_addr, end_addr, flags;
460c752998bSGaetan Rivet 	int fd, i;
461c752998bSGaetan Rivet 	void *addr;
462c752998bSGaetan Rivet 
463c752998bSGaetan Rivet 	/* open and read addresses of the corresponding resource in sysfs */
464c752998bSGaetan Rivet 	snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource",
465c52dd394SThomas Monjalon 		rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
466c752998bSGaetan Rivet 		dev->addr.devid, dev->addr.function);
467c752998bSGaetan Rivet 	f = fopen(filename, "r");
468c752998bSGaetan Rivet 	if (f == NULL) {
469c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot open sysfs resource: %s\n",
470c752998bSGaetan Rivet 			strerror(errno));
471c752998bSGaetan Rivet 		return -1;
472c752998bSGaetan Rivet 	}
473c752998bSGaetan Rivet 	for (i = 0; i < bar + 1; i++) {
474c752998bSGaetan Rivet 		if (fgets(buf, sizeof(buf), f) == NULL) {
475c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "Cannot read sysfs resource\n");
476c752998bSGaetan Rivet 			goto error;
477c752998bSGaetan Rivet 		}
478c752998bSGaetan Rivet 	}
479c752998bSGaetan Rivet 	if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr,
480c752998bSGaetan Rivet 			&end_addr, &flags) < 0)
481c752998bSGaetan Rivet 		goto error;
482c752998bSGaetan Rivet 	if ((flags & IORESOURCE_IO) == 0) {
483c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "BAR %d is not an IO resource\n", bar);
484c752998bSGaetan Rivet 		goto error;
485c752998bSGaetan Rivet 	}
486c752998bSGaetan Rivet 	snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource%d",
487c52dd394SThomas Monjalon 		rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
488c752998bSGaetan Rivet 		dev->addr.devid, dev->addr.function, bar);
489c752998bSGaetan Rivet 
490c752998bSGaetan Rivet 	/* mmap the pci resource */
491c752998bSGaetan Rivet 	fd = open(filename, O_RDWR);
492c752998bSGaetan Rivet 	if (fd < 0) {
493c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot open %s: %s\n", filename,
494c752998bSGaetan Rivet 			strerror(errno));
495c752998bSGaetan Rivet 		goto error;
496c752998bSGaetan Rivet 	}
497c752998bSGaetan Rivet 	addr = mmap(NULL, end_addr + 1, PROT_READ | PROT_WRITE,
498c752998bSGaetan Rivet 		MAP_SHARED, fd, 0);
499c752998bSGaetan Rivet 	close(fd);
500c752998bSGaetan Rivet 	if (addr == MAP_FAILED) {
501c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot mmap IO port resource: %s\n",
502c752998bSGaetan Rivet 			strerror(errno));
503c752998bSGaetan Rivet 		goto error;
504c752998bSGaetan Rivet 	}
505c752998bSGaetan Rivet 
506c752998bSGaetan Rivet 	/* strangely, the base address is mmap addr + phys_addr */
507c752998bSGaetan Rivet 	p->base = (uintptr_t)addr + phys_addr;
508c752998bSGaetan Rivet 	p->len = end_addr + 1;
509c752998bSGaetan Rivet 	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%"PRIx64"\n", p->base);
510c752998bSGaetan Rivet 	fclose(f);
511c752998bSGaetan Rivet 
512c752998bSGaetan Rivet 	return 0;
513c752998bSGaetan Rivet 
514c752998bSGaetan Rivet error:
515c752998bSGaetan Rivet 	fclose(f);
516c752998bSGaetan Rivet 	return -1;
517c752998bSGaetan Rivet }
518c752998bSGaetan Rivet #endif
519c752998bSGaetan Rivet 
520c752998bSGaetan Rivet void
521c752998bSGaetan Rivet pci_uio_ioport_read(struct rte_pci_ioport *p,
522c752998bSGaetan Rivet 		    void *data, size_t len, off_t offset)
523c752998bSGaetan Rivet {
524c752998bSGaetan Rivet 	uint8_t *d;
525c752998bSGaetan Rivet 	int size;
526c752998bSGaetan Rivet 	uintptr_t reg = p->base + offset;
527c752998bSGaetan Rivet 
528c752998bSGaetan Rivet 	for (d = data; len > 0; d += size, reg += size, len -= size) {
529c752998bSGaetan Rivet 		if (len >= 4) {
530c752998bSGaetan Rivet 			size = 4;
531c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
532c752998bSGaetan Rivet 			*(uint32_t *)d = inl(reg);
533c752998bSGaetan Rivet #else
534c752998bSGaetan Rivet 			*(uint32_t *)d = *(volatile uint32_t *)reg;
535c752998bSGaetan Rivet #endif
536c752998bSGaetan Rivet 		} else if (len >= 2) {
537c752998bSGaetan Rivet 			size = 2;
538c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
539c752998bSGaetan Rivet 			*(uint16_t *)d = inw(reg);
540c752998bSGaetan Rivet #else
541c752998bSGaetan Rivet 			*(uint16_t *)d = *(volatile uint16_t *)reg;
542c752998bSGaetan Rivet #endif
543c752998bSGaetan Rivet 		} else {
544c752998bSGaetan Rivet 			size = 1;
545c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
546c752998bSGaetan Rivet 			*d = inb(reg);
547c752998bSGaetan Rivet #else
548c752998bSGaetan Rivet 			*d = *(volatile uint8_t *)reg;
549c752998bSGaetan Rivet #endif
550c752998bSGaetan Rivet 		}
551c752998bSGaetan Rivet 	}
552c752998bSGaetan Rivet }
553c752998bSGaetan Rivet 
554c752998bSGaetan Rivet void
555c752998bSGaetan Rivet pci_uio_ioport_write(struct rte_pci_ioport *p,
556c752998bSGaetan Rivet 		     const void *data, size_t len, off_t offset)
557c752998bSGaetan Rivet {
558c752998bSGaetan Rivet 	const uint8_t *s;
559c752998bSGaetan Rivet 	int size;
560c752998bSGaetan Rivet 	uintptr_t reg = p->base + offset;
561c752998bSGaetan Rivet 
562c752998bSGaetan Rivet 	for (s = data; len > 0; s += size, reg += size, len -= size) {
563c752998bSGaetan Rivet 		if (len >= 4) {
564c752998bSGaetan Rivet 			size = 4;
565c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
566c752998bSGaetan Rivet 			outl_p(*(const uint32_t *)s, reg);
567c752998bSGaetan Rivet #else
568c752998bSGaetan Rivet 			*(volatile uint32_t *)reg = *(const uint32_t *)s;
569c752998bSGaetan Rivet #endif
570c752998bSGaetan Rivet 		} else if (len >= 2) {
571c752998bSGaetan Rivet 			size = 2;
572c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
573c752998bSGaetan Rivet 			outw_p(*(const uint16_t *)s, reg);
574c752998bSGaetan Rivet #else
575c752998bSGaetan Rivet 			*(volatile uint16_t *)reg = *(const uint16_t *)s;
576c752998bSGaetan Rivet #endif
577c752998bSGaetan Rivet 		} else {
578c752998bSGaetan Rivet 			size = 1;
579c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
580c752998bSGaetan Rivet 			outb_p(*s, reg);
581c752998bSGaetan Rivet #else
582c752998bSGaetan Rivet 			*(volatile uint8_t *)reg = *s;
583c752998bSGaetan Rivet #endif
584c752998bSGaetan Rivet 		}
585c752998bSGaetan Rivet 	}
586c752998bSGaetan Rivet }
587c752998bSGaetan Rivet 
588c752998bSGaetan Rivet int
589c752998bSGaetan Rivet pci_uio_ioport_unmap(struct rte_pci_ioport *p)
590c752998bSGaetan Rivet {
591c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
592c752998bSGaetan Rivet 	RTE_SET_USED(p);
593c752998bSGaetan Rivet 	/* FIXME close intr fd ? */
594c752998bSGaetan Rivet 	return 0;
595c752998bSGaetan Rivet #else
596c752998bSGaetan Rivet 	return munmap((void *)(uintptr_t)p->base, p->len);
597c752998bSGaetan Rivet #endif
598c752998bSGaetan Rivet }
599