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