xref: /dpdk/drivers/bus/pci/linux/pci_uio.c (revision 847d78fb9530fff401bf167298aad22766a1f04a)
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 
14c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
15c752998bSGaetan Rivet #include <sys/io.h>
16c752998bSGaetan Rivet #endif
17c752998bSGaetan Rivet 
186723c0fcSBruce Richardson #include <rte_string_fns.h>
19c752998bSGaetan Rivet #include <rte_log.h>
20c752998bSGaetan Rivet #include <rte_pci.h>
21c752998bSGaetan Rivet #include <rte_bus_pci.h>
22c752998bSGaetan Rivet #include <rte_common.h>
23c752998bSGaetan Rivet #include <rte_malloc.h>
24c752998bSGaetan Rivet 
25c752998bSGaetan Rivet #include "eal_filesystem.h"
26c752998bSGaetan Rivet #include "pci_init.h"
27e1ece609SDavid Marchand #include "private.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 {
37d61138d4SHarman Kalra 	int uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
38d61138d4SHarman Kalra 
39aedd054cSHarman Kalra 	if (uio_cfg_fd < 0)
40aedd054cSHarman Kalra 		return -1;
41aedd054cSHarman Kalra 
42d61138d4SHarman Kalra 	return pread(uio_cfg_fd, buf, len, offset);
43c752998bSGaetan Rivet }
44c752998bSGaetan Rivet 
45c752998bSGaetan Rivet int
46c752998bSGaetan Rivet pci_uio_write_config(const struct rte_intr_handle *intr_handle,
47c752998bSGaetan Rivet 		     const void *buf, size_t len, off_t offset)
48c752998bSGaetan Rivet {
49d61138d4SHarman Kalra 	int uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
50d61138d4SHarman Kalra 
51aedd054cSHarman Kalra 	if (uio_cfg_fd < 0)
52aedd054cSHarman Kalra 		return -1;
53aedd054cSHarman Kalra 
54d61138d4SHarman Kalra 	return pwrite(uio_cfg_fd, buf, len, offset);
55c752998bSGaetan Rivet }
56c752998bSGaetan Rivet 
57095cf6e6SChenbo Xia int
58095cf6e6SChenbo Xia pci_uio_mmio_read(const struct rte_pci_device *dev, int bar,
59095cf6e6SChenbo Xia 		  void *buf, size_t len, off_t offset)
60095cf6e6SChenbo Xia {
61095cf6e6SChenbo Xia 	if (bar >= PCI_MAX_RESOURCE || dev->mem_resource[bar].addr == NULL ||
62095cf6e6SChenbo Xia 			(uint64_t)offset + len > dev->mem_resource[bar].len)
63095cf6e6SChenbo Xia 		return -1;
64095cf6e6SChenbo Xia 	memcpy(buf, (uint8_t *)dev->mem_resource[bar].addr + offset, len);
65095cf6e6SChenbo Xia 	return len;
66095cf6e6SChenbo Xia }
67095cf6e6SChenbo Xia 
68095cf6e6SChenbo Xia int
69095cf6e6SChenbo Xia pci_uio_mmio_write(const struct rte_pci_device *dev, int bar,
70095cf6e6SChenbo Xia 		   const void *buf, size_t len, off_t offset)
71095cf6e6SChenbo Xia {
72095cf6e6SChenbo Xia 	if (bar >= PCI_MAX_RESOURCE || dev->mem_resource[bar].addr == NULL ||
73095cf6e6SChenbo Xia 			(uint64_t)offset + len > dev->mem_resource[bar].len)
74095cf6e6SChenbo Xia 		return -1;
75095cf6e6SChenbo Xia 	memcpy((uint8_t *)dev->mem_resource[bar].addr + offset, buf, len);
76095cf6e6SChenbo Xia 	return len;
77095cf6e6SChenbo Xia }
78095cf6e6SChenbo Xia 
79c752998bSGaetan Rivet static int
80c752998bSGaetan Rivet pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num)
81c752998bSGaetan Rivet {
82c752998bSGaetan Rivet 	FILE *f;
83c752998bSGaetan Rivet 	char filename[PATH_MAX];
84c752998bSGaetan Rivet 	int ret;
85c752998bSGaetan Rivet 	unsigned major, minor;
86c752998bSGaetan Rivet 	dev_t dev;
87c752998bSGaetan Rivet 
88c752998bSGaetan Rivet 	/* get the name of the sysfs file that contains the major and minor
89c752998bSGaetan Rivet 	 * of the uio device and read its content */
90c752998bSGaetan Rivet 	snprintf(filename, sizeof(filename), "%s/dev", sysfs_uio_path);
91c752998bSGaetan Rivet 
92c752998bSGaetan Rivet 	f = fopen(filename, "r");
93c752998bSGaetan Rivet 	if (f == NULL) {
94849f773bSDavid Marchand 		PCI_LOG(ERR, "%s(): cannot open sysfs to get major:minor", __func__);
95c752998bSGaetan Rivet 		return -1;
96c752998bSGaetan Rivet 	}
97c752998bSGaetan Rivet 
98c752998bSGaetan Rivet 	ret = fscanf(f, "%u:%u", &major, &minor);
99c752998bSGaetan Rivet 	if (ret != 2) {
100849f773bSDavid Marchand 		PCI_LOG(ERR, "%s(): cannot parse sysfs to get major:minor", __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) {
111849f773bSDavid Marchand 		PCI_LOG(ERR, "%s(): mknod() failed %s", __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) {
150849f773bSDavid Marchand 			PCI_LOG(ERR, "Cannot opendir %s", 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)
191849f773bSDavid Marchand 		PCI_LOG(WARNING, "Cannot create /dev/uio%u", 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 {
200d61138d4SHarman Kalra 	int uio_cfg_fd = rte_intr_dev_fd_get(dev->intr_handle);
201d61138d4SHarman Kalra 
202c752998bSGaetan Rivet 	rte_free(uio_res);
203c752998bSGaetan Rivet 
204d61138d4SHarman Kalra 	if (uio_cfg_fd >= 0) {
205d61138d4SHarman Kalra 		close(uio_cfg_fd);
206d61138d4SHarman Kalra 		rte_intr_dev_fd_set(dev->intr_handle, -1);
207c752998bSGaetan Rivet 	}
208d61138d4SHarman Kalra 
209d61138d4SHarman Kalra 	if (rte_intr_fd_get(dev->intr_handle) >= 0) {
210d61138d4SHarman Kalra 		close(rte_intr_fd_get(dev->intr_handle));
211d61138d4SHarman Kalra 		rte_intr_fd_set(dev->intr_handle, -1);
212d61138d4SHarman Kalra 		rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
213c752998bSGaetan Rivet 	}
214c752998bSGaetan Rivet }
215c752998bSGaetan Rivet 
216c752998bSGaetan Rivet int
217c752998bSGaetan Rivet pci_uio_alloc_resource(struct rte_pci_device *dev,
218c752998bSGaetan Rivet 		struct mapped_pci_resource **uio_res)
219c752998bSGaetan Rivet {
220c752998bSGaetan Rivet 	char dirname[PATH_MAX];
221c752998bSGaetan Rivet 	char cfgname[PATH_MAX];
222c752998bSGaetan Rivet 	char devname[PATH_MAX]; /* contains the /dev/uioX */
223d61138d4SHarman Kalra 	int uio_num, fd, uio_cfg_fd;
224c752998bSGaetan Rivet 	struct rte_pci_addr *loc;
225c752998bSGaetan Rivet 
226c752998bSGaetan Rivet 	loc = &dev->addr;
227c752998bSGaetan Rivet 
228c752998bSGaetan Rivet 	/* find uio resource */
229c752998bSGaetan Rivet 	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 1);
230c752998bSGaetan Rivet 	if (uio_num < 0) {
231849f773bSDavid Marchand 		PCI_LOG(WARNING, "  "PCI_PRI_FMT" not managed by UIO driver, skipping",
232849f773bSDavid Marchand 			loc->domain, loc->bus, loc->devid, loc->function);
233c752998bSGaetan Rivet 		return 1;
234c752998bSGaetan Rivet 	}
235c752998bSGaetan Rivet 	snprintf(devname, sizeof(devname), "/dev/uio%u", uio_num);
236c752998bSGaetan Rivet 
237*847d78fbSZerun Fu 	/* save fd */
238d61138d4SHarman Kalra 	fd = open(devname, O_RDWR);
239d61138d4SHarman Kalra 	if (fd < 0) {
240849f773bSDavid Marchand 		PCI_LOG(ERR, "Cannot open %s: %s", devname, strerror(errno));
241c752998bSGaetan Rivet 		goto error;
242c752998bSGaetan Rivet 	}
243c752998bSGaetan Rivet 
244d61138d4SHarman Kalra 	if (rte_intr_fd_set(dev->intr_handle, fd))
245d61138d4SHarman Kalra 		goto error;
246d61138d4SHarman Kalra 
247c752998bSGaetan Rivet 	snprintf(cfgname, sizeof(cfgname),
248c752998bSGaetan Rivet 			"/sys/class/uio/uio%u/device/config", uio_num);
249d61138d4SHarman Kalra 
250d61138d4SHarman Kalra 	uio_cfg_fd = open(cfgname, O_RDWR);
251d61138d4SHarman Kalra 	if (uio_cfg_fd < 0) {
252849f773bSDavid Marchand 		PCI_LOG(ERR, "Cannot open %s: %s", cfgname, strerror(errno));
253c752998bSGaetan Rivet 		goto error;
254c752998bSGaetan Rivet 	}
255c752998bSGaetan Rivet 
256d61138d4SHarman Kalra 	if (rte_intr_dev_fd_set(dev->intr_handle, uio_cfg_fd))
257d61138d4SHarman Kalra 		goto error;
258d61138d4SHarman Kalra 
259d61138d4SHarman Kalra 	if (dev->kdrv == RTE_PCI_KDRV_IGB_UIO) {
260d61138d4SHarman Kalra 		if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO))
261d61138d4SHarman Kalra 			goto error;
262d61138d4SHarman Kalra 	} else {
263d61138d4SHarman Kalra 		if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO_INTX))
264d61138d4SHarman Kalra 			goto error;
265c752998bSGaetan Rivet 
266c752998bSGaetan Rivet 		/* set bus master that is not done by uio_pci_generic */
267b3d590a0SDavid Marchand 		if (rte_pci_set_bus_master(dev, true)) {
268849f773bSDavid Marchand 			PCI_LOG(ERR, "Cannot set up bus mastering!");
269c752998bSGaetan Rivet 			goto error;
270c752998bSGaetan Rivet 		}
271c752998bSGaetan Rivet 	}
272c752998bSGaetan Rivet 
273*847d78fbSZerun Fu 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
274*847d78fbSZerun Fu 		return 0;
275*847d78fbSZerun Fu 
276c752998bSGaetan Rivet 	/* allocate the mapping details for secondary processes*/
277c752998bSGaetan Rivet 	*uio_res = rte_zmalloc("UIO_RES", sizeof(**uio_res), 0);
278c752998bSGaetan Rivet 	if (*uio_res == NULL) {
279849f773bSDavid Marchand 		PCI_LOG(ERR, "%s(): cannot store uio mmap details", __func__);
280c752998bSGaetan Rivet 		goto error;
281c752998bSGaetan Rivet 	}
282c752998bSGaetan Rivet 
2836723c0fcSBruce Richardson 	strlcpy((*uio_res)->path, devname, sizeof((*uio_res)->path));
284c752998bSGaetan Rivet 	memcpy(&(*uio_res)->pci_addr, &dev->addr, sizeof((*uio_res)->pci_addr));
285c752998bSGaetan Rivet 
286c752998bSGaetan Rivet 	return 0;
287c752998bSGaetan Rivet 
288c752998bSGaetan Rivet error:
289c752998bSGaetan Rivet 	pci_uio_free_resource(dev, *uio_res);
290c752998bSGaetan Rivet 	return -1;
291c752998bSGaetan Rivet }
292c752998bSGaetan Rivet 
293c752998bSGaetan Rivet int
294c752998bSGaetan Rivet pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,
295c752998bSGaetan Rivet 		struct mapped_pci_resource *uio_res, int map_idx)
296c752998bSGaetan Rivet {
2974a928ef9SRafal Kozik 	int fd = -1;
298c752998bSGaetan Rivet 	char devname[PATH_MAX];
299c752998bSGaetan Rivet 	void *mapaddr;
300c752998bSGaetan Rivet 	struct rte_pci_addr *loc;
301c752998bSGaetan Rivet 	struct pci_map *maps;
3024a928ef9SRafal Kozik 	int wc_activate = 0;
3034a928ef9SRafal Kozik 
3044a928ef9SRafal Kozik 	if (dev->driver != NULL)
3054a928ef9SRafal Kozik 		wc_activate = dev->driver->drv_flags & RTE_PCI_DRV_WC_ACTIVATE;
306c752998bSGaetan Rivet 
307c752998bSGaetan Rivet 	loc = &dev->addr;
308c752998bSGaetan Rivet 	maps = uio_res->maps;
309c752998bSGaetan Rivet 
310c752998bSGaetan Rivet 	/* allocate memory to keep path */
311d3110b12SFerruh Yigit 	maps[map_idx].path = rte_malloc(NULL, sizeof(devname), 0);
312c752998bSGaetan Rivet 	if (maps[map_idx].path == NULL) {
313849f773bSDavid Marchand 		PCI_LOG(ERR, "Cannot allocate memory for path: %s", strerror(errno));
314c752998bSGaetan Rivet 		return -1;
315c752998bSGaetan Rivet 	}
316c752998bSGaetan Rivet 
317c752998bSGaetan Rivet 	/*
318c752998bSGaetan Rivet 	 * open resource file, to mmap it
319c752998bSGaetan Rivet 	 */
3204a928ef9SRafal Kozik 	if (wc_activate) {
3214a928ef9SRafal Kozik 		/* update devname for mmap  */
3224a928ef9SRafal Kozik 		snprintf(devname, sizeof(devname),
3234a928ef9SRafal Kozik 			"%s/" PCI_PRI_FMT "/resource%d_wc",
3244a928ef9SRafal Kozik 			rte_pci_get_sysfs_path(),
3254a928ef9SRafal Kozik 			loc->domain, loc->bus, loc->devid,
3264a928ef9SRafal Kozik 			loc->function, res_idx);
3274a928ef9SRafal Kozik 
3284a928ef9SRafal Kozik 		fd = open(devname, O_RDWR);
329c530aa78SStephen Hemminger 		if (fd < 0 && errno != ENOENT) {
330849f773bSDavid Marchand 			PCI_LOG(INFO, "%s cannot be mapped. Fall-back to non prefetchable mode.",
3314a928ef9SRafal Kozik 				devname);
3324a928ef9SRafal Kozik 		}
3334a928ef9SRafal Kozik 	}
3344a928ef9SRafal Kozik 
3354a928ef9SRafal Kozik 	if (!wc_activate || fd < 0) {
3364a928ef9SRafal Kozik 		snprintf(devname, sizeof(devname),
3374a928ef9SRafal Kozik 			"%s/" PCI_PRI_FMT "/resource%d",
3384a928ef9SRafal Kozik 			rte_pci_get_sysfs_path(),
3394a928ef9SRafal Kozik 			loc->domain, loc->bus, loc->devid,
3404a928ef9SRafal Kozik 			loc->function, res_idx);
3414a928ef9SRafal Kozik 
3424a928ef9SRafal Kozik 		/* then try to map resource file */
343c752998bSGaetan Rivet 		fd = open(devname, O_RDWR);
344c752998bSGaetan Rivet 		if (fd < 0) {
345849f773bSDavid Marchand 			PCI_LOG(ERR, "Cannot open %s: %s", devname, strerror(errno));
346c752998bSGaetan Rivet 			goto error;
347c752998bSGaetan Rivet 		}
3484a928ef9SRafal Kozik 	}
349c752998bSGaetan Rivet 
350c752998bSGaetan Rivet 	/* try mapping somewhere close to the end of hugepages */
351c752998bSGaetan Rivet 	if (pci_map_addr == NULL)
352c752998bSGaetan Rivet 		pci_map_addr = pci_find_max_end_va();
353c752998bSGaetan Rivet 
354c752998bSGaetan Rivet 	mapaddr = pci_map_resource(pci_map_addr, fd, 0,
355c752998bSGaetan Rivet 			(size_t)dev->mem_resource[res_idx].len, 0);
356c752998bSGaetan Rivet 	close(fd);
357e200535cSDavid Marchand 	if (mapaddr == NULL)
358c752998bSGaetan Rivet 		goto error;
359c752998bSGaetan Rivet 
360c752998bSGaetan Rivet 	pci_map_addr = RTE_PTR_ADD(mapaddr,
361c752998bSGaetan Rivet 			(size_t)dev->mem_resource[res_idx].len);
362c752998bSGaetan Rivet 
363d25ab4b7SWangyu (Eric) 	pci_map_addr = RTE_PTR_ALIGN(pci_map_addr, sysconf(_SC_PAGE_SIZE));
364d25ab4b7SWangyu (Eric) 
365c752998bSGaetan Rivet 	maps[map_idx].phaddr = dev->mem_resource[res_idx].phys_addr;
366c752998bSGaetan Rivet 	maps[map_idx].size = dev->mem_resource[res_idx].len;
367c752998bSGaetan Rivet 	maps[map_idx].addr = mapaddr;
368c752998bSGaetan Rivet 	maps[map_idx].offset = 0;
369c752998bSGaetan Rivet 	strcpy(maps[map_idx].path, devname);
370c752998bSGaetan Rivet 	dev->mem_resource[res_idx].addr = mapaddr;
371c752998bSGaetan Rivet 
372c752998bSGaetan Rivet 	return 0;
373c752998bSGaetan Rivet 
374c752998bSGaetan Rivet error:
375c752998bSGaetan Rivet 	rte_free(maps[map_idx].path);
376c752998bSGaetan Rivet 	return -1;
377c752998bSGaetan Rivet }
378c752998bSGaetan Rivet 
379df58e45eSHuawei Xie #define PIO_MAX 0x10000
380df58e45eSHuawei Xie 
381c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
382c752998bSGaetan Rivet int
383c752998bSGaetan Rivet pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
384c752998bSGaetan Rivet 		   struct rte_pci_ioport *p)
385c752998bSGaetan Rivet {
38646dcbccdSHuawei Xie 	FILE *f = NULL;
387c752998bSGaetan Rivet 	char dirname[PATH_MAX];
388c752998bSGaetan Rivet 	char filename[PATH_MAX];
38946dcbccdSHuawei Xie 	char buf[BUFSIZ];
39046dcbccdSHuawei Xie 	uint64_t phys_addr, end_addr, flags;
39146dcbccdSHuawei Xie 	unsigned long base;
392d61138d4SHarman Kalra 	int i, fd;
393c752998bSGaetan Rivet 
39446dcbccdSHuawei Xie 	/* open and read addresses of the corresponding resource in sysfs */
39546dcbccdSHuawei Xie 	snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource",
39646dcbccdSHuawei Xie 		rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
39746dcbccdSHuawei Xie 		dev->addr.devid, dev->addr.function);
39846dcbccdSHuawei Xie 	f = fopen(filename, "r");
39946dcbccdSHuawei Xie 	if (f == NULL) {
400849f773bSDavid Marchand 		PCI_LOG(ERR, "%s(): Cannot open sysfs resource: %s", __func__, strerror(errno));
401c752998bSGaetan Rivet 		return -1;
402c752998bSGaetan Rivet 	}
40346dcbccdSHuawei Xie 
40446dcbccdSHuawei Xie 	for (i = 0; i < bar + 1; i++) {
40546dcbccdSHuawei Xie 		if (fgets(buf, sizeof(buf), f) == NULL) {
406849f773bSDavid Marchand 			PCI_LOG(ERR, "%s(): Cannot read sysfs resource", __func__);
40746dcbccdSHuawei Xie 			goto error;
40846dcbccdSHuawei Xie 		}
40946dcbccdSHuawei Xie 	}
41046dcbccdSHuawei Xie 	if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr,
41146dcbccdSHuawei Xie 		&end_addr, &flags) < 0)
41246dcbccdSHuawei Xie 		goto error;
41346dcbccdSHuawei Xie 
414df58e45eSHuawei Xie 	if (flags & IORESOURCE_IO) {
415df58e45eSHuawei Xie 		if (rte_eal_iopl_init()) {
416849f773bSDavid Marchand 			PCI_LOG(ERR, "%s(): insufficient ioport permissions for PCI device %s",
417df58e45eSHuawei Xie 				__func__, dev->name);
41846dcbccdSHuawei Xie 			goto error;
41946dcbccdSHuawei Xie 		}
42046dcbccdSHuawei Xie 
421df58e45eSHuawei Xie 		base = (unsigned long)phys_addr;
422df58e45eSHuawei Xie 		if (base > PIO_MAX) {
423849f773bSDavid Marchand 			PCI_LOG(ERR, "%s(): %08lx too large PIO resource", __func__, base);
42446dcbccdSHuawei Xie 			goto error;
425df58e45eSHuawei Xie 		}
426df58e45eSHuawei Xie 
427849f773bSDavid Marchand 		PCI_LOG(DEBUG, "%s(): PIO BAR %08lx detected", __func__, base);
428df58e45eSHuawei Xie 	} else if (flags & IORESOURCE_MEM) {
429df58e45eSHuawei Xie 		base = (unsigned long)dev->mem_resource[bar].addr;
430849f773bSDavid Marchand 		PCI_LOG(DEBUG, "%s(): MMIO BAR %08lx detected", __func__, base);
431df58e45eSHuawei Xie 	} else {
432849f773bSDavid Marchand 		PCI_LOG(ERR, "%s(): unknown BAR type", __func__);
433df58e45eSHuawei Xie 		goto error;
434df58e45eSHuawei Xie 	}
435c752998bSGaetan Rivet 
436c752998bSGaetan Rivet 	/* FIXME only for primary process ? */
437d61138d4SHarman Kalra 	if (rte_intr_type_get(dev->intr_handle) ==
438d61138d4SHarman Kalra 					RTE_INTR_HANDLE_UNKNOWN) {
43946dcbccdSHuawei Xie 		int uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
44046dcbccdSHuawei Xie 		if (uio_num < 0) {
441849f773bSDavid Marchand 			PCI_LOG(ERR, "cannot open %s: %s", dirname, strerror(errno));
44246dcbccdSHuawei Xie 			goto error;
44346dcbccdSHuawei Xie 		}
444c752998bSGaetan Rivet 
445c752998bSGaetan Rivet 		snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num);
446d61138d4SHarman Kalra 		fd = open(filename, O_RDWR);
447d61138d4SHarman Kalra 		if (fd < 0) {
448849f773bSDavid Marchand 			PCI_LOG(ERR, "Cannot open %s: %s", filename, strerror(errno));
44946dcbccdSHuawei Xie 			goto error;
450c752998bSGaetan Rivet 		}
451d61138d4SHarman Kalra 		if (rte_intr_fd_set(dev->intr_handle, fd))
452d61138d4SHarman Kalra 			goto error;
453d61138d4SHarman Kalra 
454d61138d4SHarman Kalra 		if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO))
455d61138d4SHarman Kalra 			goto error;
456c752998bSGaetan Rivet 	}
457c752998bSGaetan Rivet 
458849f773bSDavid Marchand 	PCI_LOG(DEBUG, "PCI Port IO found start=0x%lx", base);
459c752998bSGaetan Rivet 
46046dcbccdSHuawei Xie 	p->base = base;
461c752998bSGaetan Rivet 	p->len = 0;
46246dcbccdSHuawei Xie 	fclose(f);
463c752998bSGaetan Rivet 	return 0;
46446dcbccdSHuawei Xie error:
46546dcbccdSHuawei Xie 	if (f)
46646dcbccdSHuawei Xie 		fclose(f);
46746dcbccdSHuawei Xie 	return -1;
468c752998bSGaetan Rivet }
469c752998bSGaetan Rivet #else
470c752998bSGaetan Rivet int
471c752998bSGaetan Rivet pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
472c752998bSGaetan Rivet 		   struct rte_pci_ioport *p)
473c752998bSGaetan Rivet {
474c752998bSGaetan Rivet 	FILE *f;
475c752998bSGaetan Rivet 	char buf[BUFSIZ];
476c752998bSGaetan Rivet 	char filename[PATH_MAX];
477c752998bSGaetan Rivet 	uint64_t phys_addr, end_addr, flags;
478c752998bSGaetan Rivet 	int fd, i;
479c752998bSGaetan Rivet 	void *addr;
480c752998bSGaetan Rivet 
481c752998bSGaetan Rivet 	/* open and read addresses of the corresponding resource in sysfs */
482c752998bSGaetan Rivet 	snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource",
483c52dd394SThomas Monjalon 		rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
484c752998bSGaetan Rivet 		dev->addr.devid, dev->addr.function);
485c752998bSGaetan Rivet 	f = fopen(filename, "r");
486c752998bSGaetan Rivet 	if (f == NULL) {
487849f773bSDavid Marchand 		PCI_LOG(ERR, "Cannot open sysfs resource: %s", strerror(errno));
488c752998bSGaetan Rivet 		return -1;
489c752998bSGaetan Rivet 	}
490c752998bSGaetan Rivet 	for (i = 0; i < bar + 1; i++) {
491c752998bSGaetan Rivet 		if (fgets(buf, sizeof(buf), f) == NULL) {
492849f773bSDavid Marchand 			PCI_LOG(ERR, "Cannot read sysfs resource");
493c752998bSGaetan Rivet 			goto error;
494c752998bSGaetan Rivet 		}
495c752998bSGaetan Rivet 	}
496c752998bSGaetan Rivet 	if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr,
497c752998bSGaetan Rivet 			&end_addr, &flags) < 0)
498c752998bSGaetan Rivet 		goto error;
499c752998bSGaetan Rivet 	if ((flags & IORESOURCE_IO) == 0) {
500849f773bSDavid Marchand 		PCI_LOG(ERR, "BAR %d is not an IO resource", bar);
501c752998bSGaetan Rivet 		goto error;
502c752998bSGaetan Rivet 	}
503c752998bSGaetan Rivet 	snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource%d",
504c52dd394SThomas Monjalon 		rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
505c752998bSGaetan Rivet 		dev->addr.devid, dev->addr.function, bar);
506c752998bSGaetan Rivet 
507c752998bSGaetan Rivet 	/* mmap the pci resource */
508c752998bSGaetan Rivet 	fd = open(filename, O_RDWR);
509c752998bSGaetan Rivet 	if (fd < 0) {
510849f773bSDavid Marchand 		PCI_LOG(ERR, "Cannot open %s: %s", filename, strerror(errno));
511c752998bSGaetan Rivet 		goto error;
512c752998bSGaetan Rivet 	}
513c752998bSGaetan Rivet 	addr = mmap(NULL, end_addr + 1, PROT_READ | PROT_WRITE,
514c752998bSGaetan Rivet 		MAP_SHARED, fd, 0);
515c752998bSGaetan Rivet 	close(fd);
516c752998bSGaetan Rivet 	if (addr == MAP_FAILED) {
517849f773bSDavid Marchand 		PCI_LOG(ERR, "Cannot mmap IO port resource: %s", strerror(errno));
518c752998bSGaetan Rivet 		goto error;
519c752998bSGaetan Rivet 	}
520c752998bSGaetan Rivet 
521c752998bSGaetan Rivet 	/* strangely, the base address is mmap addr + phys_addr */
522c752998bSGaetan Rivet 	p->base = (uintptr_t)addr + phys_addr;
523c752998bSGaetan Rivet 	p->len = end_addr + 1;
524849f773bSDavid Marchand 	PCI_LOG(DEBUG, "PCI Port IO found start=0x%"PRIx64, p->base);
525c752998bSGaetan Rivet 	fclose(f);
526c752998bSGaetan Rivet 
527c752998bSGaetan Rivet 	return 0;
528c752998bSGaetan Rivet 
529c752998bSGaetan Rivet error:
530c752998bSGaetan Rivet 	fclose(f);
531c752998bSGaetan Rivet 	return -1;
532c752998bSGaetan Rivet }
533c752998bSGaetan Rivet #endif
534c752998bSGaetan Rivet 
535df58e45eSHuawei Xie #if defined(RTE_ARCH_X86)
536204a7f44SThomas Monjalon 
537df58e45eSHuawei Xie static inline uint8_t ioread8(void *addr)
538df58e45eSHuawei Xie {
539df58e45eSHuawei Xie 	uint8_t val;
540df58e45eSHuawei Xie 
541df58e45eSHuawei Xie 	val = (uint64_t)(uintptr_t)addr >= PIO_MAX ?
542df58e45eSHuawei Xie 		*(volatile uint8_t *)addr :
543204a7f44SThomas Monjalon #ifdef __GLIBC__
544df58e45eSHuawei Xie 		inb_p((unsigned long)addr);
545204a7f44SThomas Monjalon #else
546204a7f44SThomas Monjalon 		inb((unsigned long)addr);
547204a7f44SThomas Monjalon #endif
548df58e45eSHuawei Xie 
549df58e45eSHuawei Xie 	return val;
550df58e45eSHuawei Xie }
551df58e45eSHuawei Xie 
552df58e45eSHuawei Xie static inline uint16_t ioread16(void *addr)
553df58e45eSHuawei Xie {
554df58e45eSHuawei Xie 	uint16_t val;
555df58e45eSHuawei Xie 
556df58e45eSHuawei Xie 	val = (uint64_t)(uintptr_t)addr >= PIO_MAX ?
557df58e45eSHuawei Xie 		*(volatile uint16_t *)addr :
558204a7f44SThomas Monjalon #ifdef __GLIBC__
559df58e45eSHuawei Xie 		inw_p((unsigned long)addr);
560204a7f44SThomas Monjalon #else
561204a7f44SThomas Monjalon 		inw((unsigned long)addr);
562204a7f44SThomas Monjalon #endif
563df58e45eSHuawei Xie 
564df58e45eSHuawei Xie 	return val;
565df58e45eSHuawei Xie }
566df58e45eSHuawei Xie 
567df58e45eSHuawei Xie static inline uint32_t ioread32(void *addr)
568df58e45eSHuawei Xie {
569df58e45eSHuawei Xie 	uint32_t val;
570df58e45eSHuawei Xie 
571df58e45eSHuawei Xie 	val = (uint64_t)(uintptr_t)addr >= PIO_MAX ?
572df58e45eSHuawei Xie 		*(volatile uint32_t *)addr :
573204a7f44SThomas Monjalon #ifdef __GLIBC__
574df58e45eSHuawei Xie 		inl_p((unsigned long)addr);
575204a7f44SThomas Monjalon #else
576204a7f44SThomas Monjalon 		inl((unsigned long)addr);
577204a7f44SThomas Monjalon #endif
578df58e45eSHuawei Xie 
579df58e45eSHuawei Xie 	return val;
580df58e45eSHuawei Xie }
581df58e45eSHuawei Xie 
582df58e45eSHuawei Xie static inline void iowrite8(uint8_t val, void *addr)
583df58e45eSHuawei Xie {
584df58e45eSHuawei Xie 	(uint64_t)(uintptr_t)addr >= PIO_MAX ?
585df58e45eSHuawei Xie 		*(volatile uint8_t *)addr = val :
586204a7f44SThomas Monjalon #ifdef __GLIBC__
587df58e45eSHuawei Xie 		outb_p(val, (unsigned long)addr);
588204a7f44SThomas Monjalon #else
589204a7f44SThomas Monjalon 		outb(val, (unsigned long)addr);
590204a7f44SThomas Monjalon #endif
591df58e45eSHuawei Xie }
592df58e45eSHuawei Xie 
593df58e45eSHuawei Xie static inline void iowrite16(uint16_t val, void *addr)
594df58e45eSHuawei Xie {
595df58e45eSHuawei Xie 	(uint64_t)(uintptr_t)addr >= PIO_MAX ?
596df58e45eSHuawei Xie 		*(volatile uint16_t *)addr = val :
597204a7f44SThomas Monjalon #ifdef __GLIBC__
598df58e45eSHuawei Xie 		outw_p(val, (unsigned long)addr);
599204a7f44SThomas Monjalon #else
600204a7f44SThomas Monjalon 		outw(val, (unsigned long)addr);
601204a7f44SThomas Monjalon #endif
602df58e45eSHuawei Xie }
603df58e45eSHuawei Xie 
604df58e45eSHuawei Xie static inline void iowrite32(uint32_t val, void *addr)
605df58e45eSHuawei Xie {
606df58e45eSHuawei Xie 	(uint64_t)(uintptr_t)addr >= PIO_MAX ?
607df58e45eSHuawei Xie 		*(volatile uint32_t *)addr = val :
608204a7f44SThomas Monjalon #ifdef __GLIBC__
609df58e45eSHuawei Xie 		outl_p(val, (unsigned long)addr);
610df58e45eSHuawei Xie #else
611204a7f44SThomas Monjalon 		outl(val, (unsigned long)addr);
612204a7f44SThomas Monjalon #endif
613204a7f44SThomas Monjalon }
614204a7f44SThomas Monjalon 
615204a7f44SThomas Monjalon #else /* !RTE_ARCH_X86 */
616204a7f44SThomas Monjalon 
617df58e45eSHuawei Xie static inline uint8_t ioread8(void *addr)
618df58e45eSHuawei Xie {
619df58e45eSHuawei Xie 	return *(volatile uint8_t *)addr;
620df58e45eSHuawei Xie }
621df58e45eSHuawei Xie 
622df58e45eSHuawei Xie static inline uint16_t ioread16(void *addr)
623df58e45eSHuawei Xie {
624df58e45eSHuawei Xie 	return *(volatile uint16_t *)addr;
625df58e45eSHuawei Xie }
626df58e45eSHuawei Xie 
627df58e45eSHuawei Xie static inline uint32_t ioread32(void *addr)
628df58e45eSHuawei Xie {
629df58e45eSHuawei Xie 	return *(volatile uint32_t *)addr;
630df58e45eSHuawei Xie }
631df58e45eSHuawei Xie 
632df58e45eSHuawei Xie static inline void iowrite8(uint8_t val, void *addr)
633df58e45eSHuawei Xie {
634df58e45eSHuawei Xie 	*(volatile uint8_t *)addr = val;
635df58e45eSHuawei Xie }
636df58e45eSHuawei Xie 
637df58e45eSHuawei Xie static inline void iowrite16(uint16_t val, void *addr)
638df58e45eSHuawei Xie {
639df58e45eSHuawei Xie 	*(volatile uint16_t *)addr = val;
640df58e45eSHuawei Xie }
641df58e45eSHuawei Xie 
642df58e45eSHuawei Xie static inline void iowrite32(uint32_t val, void *addr)
643df58e45eSHuawei Xie {
644df58e45eSHuawei Xie 	*(volatile uint32_t *)addr = val;
645df58e45eSHuawei Xie }
646204a7f44SThomas Monjalon 
647204a7f44SThomas Monjalon #endif /* !RTE_ARCH_X86 */
648df58e45eSHuawei Xie 
649c752998bSGaetan Rivet void
650c752998bSGaetan Rivet pci_uio_ioport_read(struct rte_pci_ioport *p,
651c752998bSGaetan Rivet 		    void *data, size_t len, off_t offset)
652c752998bSGaetan Rivet {
653c752998bSGaetan Rivet 	uint8_t *d;
654c752998bSGaetan Rivet 	int size;
655c752998bSGaetan Rivet 	uintptr_t reg = p->base + offset;
656c752998bSGaetan Rivet 
657c752998bSGaetan Rivet 	for (d = data; len > 0; d += size, reg += size, len -= size) {
658c752998bSGaetan Rivet 		if (len >= 4) {
659c752998bSGaetan Rivet 			size = 4;
660df58e45eSHuawei Xie 			*(uint32_t *)d = ioread32((void *)reg);
661c752998bSGaetan Rivet 		} else if (len >= 2) {
662c752998bSGaetan Rivet 			size = 2;
663df58e45eSHuawei Xie 			*(uint16_t *)d = ioread16((void *)reg);
664c752998bSGaetan Rivet 		} else {
665c752998bSGaetan Rivet 			size = 1;
666df58e45eSHuawei Xie 			*d = ioread8((void *)reg);
667c752998bSGaetan Rivet 		}
668c752998bSGaetan Rivet 	}
669c752998bSGaetan Rivet }
670c752998bSGaetan Rivet 
671c752998bSGaetan Rivet void
672c752998bSGaetan Rivet pci_uio_ioport_write(struct rte_pci_ioport *p,
673c752998bSGaetan Rivet 		     const void *data, size_t len, off_t offset)
674c752998bSGaetan Rivet {
675c752998bSGaetan Rivet 	const uint8_t *s;
676c752998bSGaetan Rivet 	int size;
677c752998bSGaetan Rivet 	uintptr_t reg = p->base + offset;
678c752998bSGaetan Rivet 
679c752998bSGaetan Rivet 	for (s = data; len > 0; s += size, reg += size, len -= size) {
680c752998bSGaetan Rivet 		if (len >= 4) {
681c752998bSGaetan Rivet 			size = 4;
682df58e45eSHuawei Xie 			iowrite32(*(const uint32_t *)s, (void *)reg);
683c752998bSGaetan Rivet 		} else if (len >= 2) {
684c752998bSGaetan Rivet 			size = 2;
685df58e45eSHuawei Xie 			iowrite16(*(const uint16_t *)s, (void *)reg);
686c752998bSGaetan Rivet 		} else {
687c752998bSGaetan Rivet 			size = 1;
688df58e45eSHuawei Xie 			iowrite8(*s, (void *)reg);
689c752998bSGaetan Rivet 		}
690c752998bSGaetan Rivet 	}
691c752998bSGaetan Rivet }
692c752998bSGaetan Rivet 
693c752998bSGaetan Rivet int
694c752998bSGaetan Rivet pci_uio_ioport_unmap(struct rte_pci_ioport *p)
695c752998bSGaetan Rivet {
696c752998bSGaetan Rivet #if defined(RTE_ARCH_X86)
697c752998bSGaetan Rivet 	RTE_SET_USED(p);
698c752998bSGaetan Rivet 	/* FIXME close intr fd ? */
699c752998bSGaetan Rivet 	return 0;
700c752998bSGaetan Rivet #else
701c752998bSGaetan Rivet 	return munmap((void *)(uintptr_t)p->base, p->len);
702c752998bSGaetan Rivet #endif
703c752998bSGaetan Rivet }
704