xref: /dpdk/drivers/bus/pci/linux/pci_uio.c (revision 6723c0fc7207ca4416822b170b1485a78aa47c7c)
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 
19*6723c0fcSBruce 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_eal_memconfig.h>
24c752998bSGaetan Rivet #include <rte_common.h>
25c752998bSGaetan Rivet #include <rte_malloc.h>
26c752998bSGaetan Rivet 
27c752998bSGaetan Rivet #include "eal_filesystem.h"
28c752998bSGaetan Rivet #include "pci_init.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 
252c752998bSGaetan Rivet 	if (dev->kdrv == RTE_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 
272*6723c0fcSBruce 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 		if (access(devname, R_OK|W_OK) != -1) {
3194a928ef9SRafal Kozik 			fd = open(devname, O_RDWR);
3204a928ef9SRafal Kozik 			if (fd < 0)
3214a928ef9SRafal Kozik 				RTE_LOG(INFO, EAL, "%s cannot be mapped. "
3224a928ef9SRafal Kozik 					"Fall-back to non prefetchable mode.\n",
3234a928ef9SRafal Kozik 					devname);
3244a928ef9SRafal Kozik 		}
3254a928ef9SRafal Kozik 	}
3264a928ef9SRafal Kozik 
3274a928ef9SRafal Kozik 	if (!wc_activate || fd < 0) {
3284a928ef9SRafal Kozik 		snprintf(devname, sizeof(devname),
3294a928ef9SRafal Kozik 			"%s/" PCI_PRI_FMT "/resource%d",
3304a928ef9SRafal Kozik 			rte_pci_get_sysfs_path(),
3314a928ef9SRafal Kozik 			loc->domain, loc->bus, loc->devid,
3324a928ef9SRafal Kozik 			loc->function, res_idx);
3334a928ef9SRafal Kozik 
3344a928ef9SRafal Kozik 		/* then try to map resource file */
335c752998bSGaetan Rivet 		fd = open(devname, O_RDWR);
336c752998bSGaetan Rivet 		if (fd < 0) {
337c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
338c752998bSGaetan Rivet 				devname, strerror(errno));
339c752998bSGaetan Rivet 			goto error;
340c752998bSGaetan Rivet 		}
3414a928ef9SRafal Kozik 	}
342c752998bSGaetan Rivet 
343c752998bSGaetan Rivet 	/* try mapping somewhere close to the end of hugepages */
344c752998bSGaetan Rivet 	if (pci_map_addr == NULL)
345c752998bSGaetan Rivet 		pci_map_addr = pci_find_max_end_va();
346c752998bSGaetan Rivet 
347c752998bSGaetan Rivet 	mapaddr = pci_map_resource(pci_map_addr, fd, 0,
348c752998bSGaetan Rivet 			(size_t)dev->mem_resource[res_idx].len, 0);
349c752998bSGaetan Rivet 	close(fd);
350c752998bSGaetan Rivet 	if (mapaddr == MAP_FAILED)
351c752998bSGaetan Rivet 		goto error;
352c752998bSGaetan Rivet 
353c752998bSGaetan Rivet 	pci_map_addr = RTE_PTR_ADD(mapaddr,
354c752998bSGaetan Rivet 			(size_t)dev->mem_resource[res_idx].len);
355c752998bSGaetan Rivet 
356c752998bSGaetan Rivet 	maps[map_idx].phaddr = dev->mem_resource[res_idx].phys_addr;
357c752998bSGaetan Rivet 	maps[map_idx].size = dev->mem_resource[res_idx].len;
358c752998bSGaetan Rivet 	maps[map_idx].addr = mapaddr;
359c752998bSGaetan Rivet 	maps[map_idx].offset = 0;
360c752998bSGaetan Rivet 	strcpy(maps[map_idx].path, devname);
361c752998bSGaetan Rivet 	dev->mem_resource[res_idx].addr = mapaddr;
362c752998bSGaetan Rivet 
363c752998bSGaetan Rivet 	return 0;
364c752998bSGaetan Rivet 
365c752998bSGaetan Rivet error:
366c752998bSGaetan Rivet 	rte_free(maps[map_idx].path);
367c752998bSGaetan Rivet 	return -1;
368c752998bSGaetan Rivet }
369c752998bSGaetan Rivet 
370c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
371c752998bSGaetan Rivet int
372c752998bSGaetan Rivet pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
373c752998bSGaetan Rivet 		   struct rte_pci_ioport *p)
374c752998bSGaetan Rivet {
375c752998bSGaetan Rivet 	char dirname[PATH_MAX];
376c752998bSGaetan Rivet 	char filename[PATH_MAX];
377c752998bSGaetan Rivet 	int uio_num;
378c752998bSGaetan Rivet 	unsigned long start;
379c752998bSGaetan Rivet 
380c752998bSGaetan Rivet 	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
381c752998bSGaetan Rivet 	if (uio_num < 0)
382c752998bSGaetan Rivet 		return -1;
383c752998bSGaetan Rivet 
384c752998bSGaetan Rivet 	/* get portio start */
385c752998bSGaetan Rivet 	snprintf(filename, sizeof(filename),
386c752998bSGaetan Rivet 		 "%s/portio/port%d/start", dirname, bar);
387c752998bSGaetan Rivet 	if (eal_parse_sysfs_value(filename, &start) < 0) {
388c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "%s(): cannot parse portio start\n",
389c752998bSGaetan Rivet 			__func__);
390c752998bSGaetan Rivet 		return -1;
391c752998bSGaetan Rivet 	}
392c752998bSGaetan Rivet 	/* ensure we don't get anything funny here, read/write will cast to
393c752998bSGaetan Rivet 	 * uin16_t */
394c752998bSGaetan Rivet 	if (start > UINT16_MAX)
395c752998bSGaetan Rivet 		return -1;
396c752998bSGaetan Rivet 
397c752998bSGaetan Rivet 	/* FIXME only for primary process ? */
398c752998bSGaetan Rivet 	if (dev->intr_handle.type == RTE_INTR_HANDLE_UNKNOWN) {
399c752998bSGaetan Rivet 
400c752998bSGaetan Rivet 		snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num);
401c752998bSGaetan Rivet 		dev->intr_handle.fd = open(filename, O_RDWR);
402c752998bSGaetan Rivet 		if (dev->intr_handle.fd < 0) {
403c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
404c752998bSGaetan Rivet 				filename, strerror(errno));
405c752998bSGaetan Rivet 			return -1;
406c752998bSGaetan Rivet 		}
407c752998bSGaetan Rivet 		dev->intr_handle.type = RTE_INTR_HANDLE_UIO;
408c752998bSGaetan Rivet 	}
409c752998bSGaetan Rivet 
410c752998bSGaetan Rivet 	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%lx\n", start);
411c752998bSGaetan Rivet 
412c752998bSGaetan Rivet 	p->base = start;
413c752998bSGaetan Rivet 	p->len = 0;
414c752998bSGaetan Rivet 	return 0;
415c752998bSGaetan Rivet }
416c752998bSGaetan Rivet #else
417c752998bSGaetan Rivet int
418c752998bSGaetan Rivet pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
419c752998bSGaetan Rivet 		   struct rte_pci_ioport *p)
420c752998bSGaetan Rivet {
421c752998bSGaetan Rivet 	FILE *f;
422c752998bSGaetan Rivet 	char buf[BUFSIZ];
423c752998bSGaetan Rivet 	char filename[PATH_MAX];
424c752998bSGaetan Rivet 	uint64_t phys_addr, end_addr, flags;
425c752998bSGaetan Rivet 	int fd, i;
426c752998bSGaetan Rivet 	void *addr;
427c752998bSGaetan Rivet 
428c752998bSGaetan Rivet 	/* open and read addresses of the corresponding resource in sysfs */
429c752998bSGaetan Rivet 	snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource",
430c52dd394SThomas Monjalon 		rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
431c752998bSGaetan Rivet 		dev->addr.devid, dev->addr.function);
432c752998bSGaetan Rivet 	f = fopen(filename, "r");
433c752998bSGaetan Rivet 	if (f == NULL) {
434c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot open sysfs resource: %s\n",
435c752998bSGaetan Rivet 			strerror(errno));
436c752998bSGaetan Rivet 		return -1;
437c752998bSGaetan Rivet 	}
438c752998bSGaetan Rivet 	for (i = 0; i < bar + 1; i++) {
439c752998bSGaetan Rivet 		if (fgets(buf, sizeof(buf), f) == NULL) {
440c752998bSGaetan Rivet 			RTE_LOG(ERR, EAL, "Cannot read sysfs resource\n");
441c752998bSGaetan Rivet 			goto error;
442c752998bSGaetan Rivet 		}
443c752998bSGaetan Rivet 	}
444c752998bSGaetan Rivet 	if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr,
445c752998bSGaetan Rivet 			&end_addr, &flags) < 0)
446c752998bSGaetan Rivet 		goto error;
447c752998bSGaetan Rivet 	if ((flags & IORESOURCE_IO) == 0) {
448c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "BAR %d is not an IO resource\n", bar);
449c752998bSGaetan Rivet 		goto error;
450c752998bSGaetan Rivet 	}
451c752998bSGaetan Rivet 	snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource%d",
452c52dd394SThomas Monjalon 		rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
453c752998bSGaetan Rivet 		dev->addr.devid, dev->addr.function, bar);
454c752998bSGaetan Rivet 
455c752998bSGaetan Rivet 	/* mmap the pci resource */
456c752998bSGaetan Rivet 	fd = open(filename, O_RDWR);
457c752998bSGaetan Rivet 	if (fd < 0) {
458c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot open %s: %s\n", filename,
459c752998bSGaetan Rivet 			strerror(errno));
460c752998bSGaetan Rivet 		goto error;
461c752998bSGaetan Rivet 	}
462c752998bSGaetan Rivet 	addr = mmap(NULL, end_addr + 1, PROT_READ | PROT_WRITE,
463c752998bSGaetan Rivet 		MAP_SHARED, fd, 0);
464c752998bSGaetan Rivet 	close(fd);
465c752998bSGaetan Rivet 	if (addr == MAP_FAILED) {
466c752998bSGaetan Rivet 		RTE_LOG(ERR, EAL, "Cannot mmap IO port resource: %s\n",
467c752998bSGaetan Rivet 			strerror(errno));
468c752998bSGaetan Rivet 		goto error;
469c752998bSGaetan Rivet 	}
470c752998bSGaetan Rivet 
471c752998bSGaetan Rivet 	/* strangely, the base address is mmap addr + phys_addr */
472c752998bSGaetan Rivet 	p->base = (uintptr_t)addr + phys_addr;
473c752998bSGaetan Rivet 	p->len = end_addr + 1;
474c752998bSGaetan Rivet 	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%"PRIx64"\n", p->base);
475c752998bSGaetan Rivet 	fclose(f);
476c752998bSGaetan Rivet 
477c752998bSGaetan Rivet 	return 0;
478c752998bSGaetan Rivet 
479c752998bSGaetan Rivet error:
480c752998bSGaetan Rivet 	fclose(f);
481c752998bSGaetan Rivet 	return -1;
482c752998bSGaetan Rivet }
483c752998bSGaetan Rivet #endif
484c752998bSGaetan Rivet 
485c752998bSGaetan Rivet void
486c752998bSGaetan Rivet pci_uio_ioport_read(struct rte_pci_ioport *p,
487c752998bSGaetan Rivet 		    void *data, size_t len, off_t offset)
488c752998bSGaetan Rivet {
489c752998bSGaetan Rivet 	uint8_t *d;
490c752998bSGaetan Rivet 	int size;
491c752998bSGaetan Rivet 	uintptr_t reg = p->base + offset;
492c752998bSGaetan Rivet 
493c752998bSGaetan Rivet 	for (d = data; len > 0; d += size, reg += size, len -= size) {
494c752998bSGaetan Rivet 		if (len >= 4) {
495c752998bSGaetan Rivet 			size = 4;
496c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
497c752998bSGaetan Rivet 			*(uint32_t *)d = inl(reg);
498c752998bSGaetan Rivet #else
499c752998bSGaetan Rivet 			*(uint32_t *)d = *(volatile uint32_t *)reg;
500c752998bSGaetan Rivet #endif
501c752998bSGaetan Rivet 		} else if (len >= 2) {
502c752998bSGaetan Rivet 			size = 2;
503c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
504c752998bSGaetan Rivet 			*(uint16_t *)d = inw(reg);
505c752998bSGaetan Rivet #else
506c752998bSGaetan Rivet 			*(uint16_t *)d = *(volatile uint16_t *)reg;
507c752998bSGaetan Rivet #endif
508c752998bSGaetan Rivet 		} else {
509c752998bSGaetan Rivet 			size = 1;
510c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
511c752998bSGaetan Rivet 			*d = inb(reg);
512c752998bSGaetan Rivet #else
513c752998bSGaetan Rivet 			*d = *(volatile uint8_t *)reg;
514c752998bSGaetan Rivet #endif
515c752998bSGaetan Rivet 		}
516c752998bSGaetan Rivet 	}
517c752998bSGaetan Rivet }
518c752998bSGaetan Rivet 
519c752998bSGaetan Rivet void
520c752998bSGaetan Rivet pci_uio_ioport_write(struct rte_pci_ioport *p,
521c752998bSGaetan Rivet 		     const void *data, size_t len, off_t offset)
522c752998bSGaetan Rivet {
523c752998bSGaetan Rivet 	const uint8_t *s;
524c752998bSGaetan Rivet 	int size;
525c752998bSGaetan Rivet 	uintptr_t reg = p->base + offset;
526c752998bSGaetan Rivet 
527c752998bSGaetan Rivet 	for (s = data; len > 0; s += size, reg += size, len -= size) {
528c752998bSGaetan Rivet 		if (len >= 4) {
529c752998bSGaetan Rivet 			size = 4;
530c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
531c752998bSGaetan Rivet 			outl_p(*(const uint32_t *)s, reg);
532c752998bSGaetan Rivet #else
533c752998bSGaetan Rivet 			*(volatile uint32_t *)reg = *(const uint32_t *)s;
534c752998bSGaetan Rivet #endif
535c752998bSGaetan Rivet 		} else if (len >= 2) {
536c752998bSGaetan Rivet 			size = 2;
537c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
538c752998bSGaetan Rivet 			outw_p(*(const uint16_t *)s, reg);
539c752998bSGaetan Rivet #else
540c752998bSGaetan Rivet 			*(volatile uint16_t *)reg = *(const uint16_t *)s;
541c752998bSGaetan Rivet #endif
542c752998bSGaetan Rivet 		} else {
543c752998bSGaetan Rivet 			size = 1;
544c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
545c752998bSGaetan Rivet 			outb_p(*s, reg);
546c752998bSGaetan Rivet #else
547c752998bSGaetan Rivet 			*(volatile uint8_t *)reg = *s;
548c752998bSGaetan Rivet #endif
549c752998bSGaetan Rivet 		}
550c752998bSGaetan Rivet 	}
551c752998bSGaetan Rivet }
552c752998bSGaetan Rivet 
553c752998bSGaetan Rivet int
554c752998bSGaetan Rivet pci_uio_ioport_unmap(struct rte_pci_ioport *p)
555c752998bSGaetan Rivet {
556c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
557c752998bSGaetan Rivet 	RTE_SET_USED(p);
558c752998bSGaetan Rivet 	/* FIXME close intr fd ? */
559c752998bSGaetan Rivet 	return 0;
560c752998bSGaetan Rivet #else
561c752998bSGaetan Rivet 	return munmap((void *)(uintptr_t)p->base, p->len);
562c752998bSGaetan Rivet #endif
563c752998bSGaetan Rivet }
564