xref: /dpdk/drivers/bus/pci/linux/pci_uio.c (revision 095cf6e68b28605635a9edb5f01991ad98474c46)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4 
5 #include <string.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <dirent.h>
9 #include <inttypes.h>
10 #include <sys/stat.h>
11 #include <sys/mman.h>
12 #include <sys/sysmacros.h>
13 #include <linux/pci_regs.h>
14 
15 #if defined(RTE_ARCH_X86)
16 #include <sys/io.h>
17 #endif
18 
19 #include <rte_string_fns.h>
20 #include <rte_log.h>
21 #include <rte_pci.h>
22 #include <rte_bus_pci.h>
23 #include <rte_common.h>
24 #include <rte_malloc.h>
25 
26 #include "eal_filesystem.h"
27 #include "pci_init.h"
28 #include "private.h"
29 
30 void *pci_map_addr = NULL;
31 
32 #define OFF_MAX              ((uint64_t)(off_t)-1)
33 
34 int
35 pci_uio_read_config(const struct rte_intr_handle *intr_handle,
36 		    void *buf, size_t len, off_t offset)
37 {
38 	int uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
39 
40 	if (uio_cfg_fd < 0)
41 		return -1;
42 
43 	return pread(uio_cfg_fd, buf, len, offset);
44 }
45 
46 int
47 pci_uio_write_config(const struct rte_intr_handle *intr_handle,
48 		     const void *buf, size_t len, off_t offset)
49 {
50 	int uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
51 
52 	if (uio_cfg_fd < 0)
53 		return -1;
54 
55 	return pwrite(uio_cfg_fd, buf, len, offset);
56 }
57 
58 int
59 pci_uio_mmio_read(const struct rte_pci_device *dev, int bar,
60 		  void *buf, size_t len, off_t offset)
61 {
62 	if (bar >= PCI_MAX_RESOURCE || dev->mem_resource[bar].addr == NULL ||
63 			(uint64_t)offset + len > dev->mem_resource[bar].len)
64 		return -1;
65 	memcpy(buf, (uint8_t *)dev->mem_resource[bar].addr + offset, len);
66 	return len;
67 }
68 
69 int
70 pci_uio_mmio_write(const struct rte_pci_device *dev, int bar,
71 		   const void *buf, size_t len, off_t offset)
72 {
73 	if (bar >= PCI_MAX_RESOURCE || dev->mem_resource[bar].addr == NULL ||
74 			(uint64_t)offset + len > dev->mem_resource[bar].len)
75 		return -1;
76 	memcpy((uint8_t *)dev->mem_resource[bar].addr + offset, buf, len);
77 	return len;
78 }
79 
80 static int
81 pci_uio_set_bus_master(int dev_fd)
82 {
83 	uint16_t reg;
84 	int ret;
85 
86 	ret = pread(dev_fd, &reg, sizeof(reg), PCI_COMMAND);
87 	if (ret != sizeof(reg)) {
88 		RTE_LOG(ERR, EAL,
89 			"Cannot read command from PCI config space!\n");
90 		return -1;
91 	}
92 
93 	/* return if bus mastering is already on */
94 	if (reg & PCI_COMMAND_MASTER)
95 		return 0;
96 
97 	reg |= PCI_COMMAND_MASTER;
98 
99 	ret = pwrite(dev_fd, &reg, sizeof(reg), PCI_COMMAND);
100 	if (ret != sizeof(reg)) {
101 		RTE_LOG(ERR, EAL,
102 			"Cannot write command to PCI config space!\n");
103 		return -1;
104 	}
105 
106 	return 0;
107 }
108 
109 static int
110 pci_mknod_uio_dev(const char *sysfs_uio_path, unsigned uio_num)
111 {
112 	FILE *f;
113 	char filename[PATH_MAX];
114 	int ret;
115 	unsigned major, minor;
116 	dev_t dev;
117 
118 	/* get the name of the sysfs file that contains the major and minor
119 	 * of the uio device and read its content */
120 	snprintf(filename, sizeof(filename), "%s/dev", sysfs_uio_path);
121 
122 	f = fopen(filename, "r");
123 	if (f == NULL) {
124 		RTE_LOG(ERR, EAL, "%s(): cannot open sysfs to get major:minor\n",
125 			__func__);
126 		return -1;
127 	}
128 
129 	ret = fscanf(f, "%u:%u", &major, &minor);
130 	if (ret != 2) {
131 		RTE_LOG(ERR, EAL, "%s(): cannot parse sysfs to get major:minor\n",
132 			__func__);
133 		fclose(f);
134 		return -1;
135 	}
136 	fclose(f);
137 
138 	/* create the char device "mknod /dev/uioX c major minor" */
139 	snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num);
140 	dev = makedev(major, minor);
141 	ret = mknod(filename, S_IFCHR | S_IRUSR | S_IWUSR, dev);
142 	if (ret != 0) {
143 		RTE_LOG(ERR, EAL, "%s(): mknod() failed %s\n",
144 			__func__, strerror(errno));
145 		return -1;
146 	}
147 
148 	return ret;
149 }
150 
151 /*
152  * Return the uioX char device used for a pci device. On success, return
153  * the UIO number and fill dstbuf string with the path of the device in
154  * sysfs. On error, return a negative value. In this case dstbuf is
155  * invalid.
156  */
157 static int
158 pci_get_uio_dev(struct rte_pci_device *dev, char *dstbuf,
159 			   unsigned int buflen, int create)
160 {
161 	struct rte_pci_addr *loc = &dev->addr;
162 	int uio_num = -1;
163 	struct dirent *e;
164 	DIR *dir;
165 	char dirname[PATH_MAX];
166 
167 	/* depending on kernel version, uio can be located in uio/uioX
168 	 * or uio:uioX */
169 
170 	snprintf(dirname, sizeof(dirname),
171 			"%s/" PCI_PRI_FMT "/uio", rte_pci_get_sysfs_path(),
172 			loc->domain, loc->bus, loc->devid, loc->function);
173 
174 	dir = opendir(dirname);
175 	if (dir == NULL) {
176 		/* retry with the parent directory */
177 		snprintf(dirname, sizeof(dirname),
178 				"%s/" PCI_PRI_FMT, rte_pci_get_sysfs_path(),
179 				loc->domain, loc->bus, loc->devid, loc->function);
180 		dir = opendir(dirname);
181 
182 		if (dir == NULL) {
183 			RTE_LOG(ERR, EAL, "Cannot opendir %s\n", dirname);
184 			return -1;
185 		}
186 	}
187 
188 	/* take the first file starting with "uio" */
189 	while ((e = readdir(dir)) != NULL) {
190 		/* format could be uio%d ...*/
191 		int shortprefix_len = sizeof("uio") - 1;
192 		/* ... or uio:uio%d */
193 		int longprefix_len = sizeof("uio:uio") - 1;
194 		char *endptr;
195 
196 		if (strncmp(e->d_name, "uio", 3) != 0)
197 			continue;
198 
199 		/* first try uio%d */
200 		errno = 0;
201 		uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10);
202 		if (errno == 0 && endptr != (e->d_name + shortprefix_len)) {
203 			snprintf(dstbuf, buflen, "%s/uio%u", dirname, uio_num);
204 			break;
205 		}
206 
207 		/* then try uio:uio%d */
208 		errno = 0;
209 		uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10);
210 		if (errno == 0 && endptr != (e->d_name + longprefix_len)) {
211 			snprintf(dstbuf, buflen, "%s/uio:uio%u", dirname, uio_num);
212 			break;
213 		}
214 	}
215 	closedir(dir);
216 
217 	/* No uio resource found */
218 	if (e == NULL)
219 		return -1;
220 
221 	/* create uio device if we've been asked to */
222 	if (rte_eal_create_uio_dev() && create &&
223 			pci_mknod_uio_dev(dstbuf, uio_num) < 0)
224 		RTE_LOG(WARNING, EAL, "Cannot create /dev/uio%u\n", uio_num);
225 
226 	return uio_num;
227 }
228 
229 void
230 pci_uio_free_resource(struct rte_pci_device *dev,
231 		struct mapped_pci_resource *uio_res)
232 {
233 	int uio_cfg_fd = rte_intr_dev_fd_get(dev->intr_handle);
234 
235 	rte_free(uio_res);
236 
237 	if (uio_cfg_fd >= 0) {
238 		close(uio_cfg_fd);
239 		rte_intr_dev_fd_set(dev->intr_handle, -1);
240 	}
241 
242 	if (rte_intr_fd_get(dev->intr_handle) >= 0) {
243 		close(rte_intr_fd_get(dev->intr_handle));
244 		rte_intr_fd_set(dev->intr_handle, -1);
245 		rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
246 	}
247 }
248 
249 int
250 pci_uio_alloc_resource(struct rte_pci_device *dev,
251 		struct mapped_pci_resource **uio_res)
252 {
253 	char dirname[PATH_MAX];
254 	char cfgname[PATH_MAX];
255 	char devname[PATH_MAX]; /* contains the /dev/uioX */
256 	int uio_num, fd, uio_cfg_fd;
257 	struct rte_pci_addr *loc;
258 
259 	loc = &dev->addr;
260 
261 	/* find uio resource */
262 	uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 1);
263 	if (uio_num < 0) {
264 		RTE_LOG(WARNING, EAL, "  "PCI_PRI_FMT" not managed by UIO driver, "
265 				"skipping\n", loc->domain, loc->bus, loc->devid, loc->function);
266 		return 1;
267 	}
268 	snprintf(devname, sizeof(devname), "/dev/uio%u", uio_num);
269 
270 	/* save fd if in primary process */
271 	fd = open(devname, O_RDWR);
272 	if (fd < 0) {
273 		RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
274 			devname, strerror(errno));
275 		goto error;
276 	}
277 
278 	if (rte_intr_fd_set(dev->intr_handle, fd))
279 		goto error;
280 
281 	snprintf(cfgname, sizeof(cfgname),
282 			"/sys/class/uio/uio%u/device/config", uio_num);
283 
284 	uio_cfg_fd = open(cfgname, O_RDWR);
285 	if (uio_cfg_fd < 0) {
286 		RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
287 			cfgname, strerror(errno));
288 		goto error;
289 	}
290 
291 	if (rte_intr_dev_fd_set(dev->intr_handle, uio_cfg_fd))
292 		goto error;
293 
294 	if (dev->kdrv == RTE_PCI_KDRV_IGB_UIO) {
295 		if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO))
296 			goto error;
297 	} else {
298 		if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO_INTX))
299 			goto error;
300 
301 		/* set bus master that is not done by uio_pci_generic */
302 		if (pci_uio_set_bus_master(uio_cfg_fd)) {
303 			RTE_LOG(ERR, EAL, "Cannot set up bus mastering!\n");
304 			goto error;
305 		}
306 	}
307 
308 	/* allocate the mapping details for secondary processes*/
309 	*uio_res = rte_zmalloc("UIO_RES", sizeof(**uio_res), 0);
310 	if (*uio_res == NULL) {
311 		RTE_LOG(ERR, EAL,
312 			"%s(): cannot store uio mmap details\n", __func__);
313 		goto error;
314 	}
315 
316 	strlcpy((*uio_res)->path, devname, sizeof((*uio_res)->path));
317 	memcpy(&(*uio_res)->pci_addr, &dev->addr, sizeof((*uio_res)->pci_addr));
318 
319 	return 0;
320 
321 error:
322 	pci_uio_free_resource(dev, *uio_res);
323 	return -1;
324 }
325 
326 int
327 pci_uio_map_resource_by_index(struct rte_pci_device *dev, int res_idx,
328 		struct mapped_pci_resource *uio_res, int map_idx)
329 {
330 	int fd = -1;
331 	char devname[PATH_MAX];
332 	void *mapaddr;
333 	struct rte_pci_addr *loc;
334 	struct pci_map *maps;
335 	int wc_activate = 0;
336 
337 	if (dev->driver != NULL)
338 		wc_activate = dev->driver->drv_flags & RTE_PCI_DRV_WC_ACTIVATE;
339 
340 	loc = &dev->addr;
341 	maps = uio_res->maps;
342 
343 	/* allocate memory to keep path */
344 	maps[map_idx].path = rte_malloc(NULL, sizeof(devname), 0);
345 	if (maps[map_idx].path == NULL) {
346 		RTE_LOG(ERR, EAL, "Cannot allocate memory for path: %s\n",
347 				strerror(errno));
348 		return -1;
349 	}
350 
351 	/*
352 	 * open resource file, to mmap it
353 	 */
354 	if (wc_activate) {
355 		/* update devname for mmap  */
356 		snprintf(devname, sizeof(devname),
357 			"%s/" PCI_PRI_FMT "/resource%d_wc",
358 			rte_pci_get_sysfs_path(),
359 			loc->domain, loc->bus, loc->devid,
360 			loc->function, res_idx);
361 
362 		fd = open(devname, O_RDWR);
363 		if (fd < 0 && errno != ENOENT) {
364 			RTE_LOG(INFO, EAL, "%s cannot be mapped. "
365 				"Fall-back to non prefetchable mode.\n",
366 				devname);
367 		}
368 	}
369 
370 	if (!wc_activate || fd < 0) {
371 		snprintf(devname, sizeof(devname),
372 			"%s/" PCI_PRI_FMT "/resource%d",
373 			rte_pci_get_sysfs_path(),
374 			loc->domain, loc->bus, loc->devid,
375 			loc->function, res_idx);
376 
377 		/* then try to map resource file */
378 		fd = open(devname, O_RDWR);
379 		if (fd < 0) {
380 			RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
381 				devname, strerror(errno));
382 			goto error;
383 		}
384 	}
385 
386 	/* try mapping somewhere close to the end of hugepages */
387 	if (pci_map_addr == NULL)
388 		pci_map_addr = pci_find_max_end_va();
389 
390 	mapaddr = pci_map_resource(pci_map_addr, fd, 0,
391 			(size_t)dev->mem_resource[res_idx].len, 0);
392 	close(fd);
393 	if (mapaddr == NULL)
394 		goto error;
395 
396 	pci_map_addr = RTE_PTR_ADD(mapaddr,
397 			(size_t)dev->mem_resource[res_idx].len);
398 
399 	pci_map_addr = RTE_PTR_ALIGN(pci_map_addr, sysconf(_SC_PAGE_SIZE));
400 
401 	maps[map_idx].phaddr = dev->mem_resource[res_idx].phys_addr;
402 	maps[map_idx].size = dev->mem_resource[res_idx].len;
403 	maps[map_idx].addr = mapaddr;
404 	maps[map_idx].offset = 0;
405 	strcpy(maps[map_idx].path, devname);
406 	dev->mem_resource[res_idx].addr = mapaddr;
407 
408 	return 0;
409 
410 error:
411 	rte_free(maps[map_idx].path);
412 	return -1;
413 }
414 
415 #define PIO_MAX 0x10000
416 
417 #if defined(RTE_ARCH_X86)
418 int
419 pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
420 		   struct rte_pci_ioport *p)
421 {
422 	FILE *f = NULL;
423 	char dirname[PATH_MAX];
424 	char filename[PATH_MAX];
425 	char buf[BUFSIZ];
426 	uint64_t phys_addr, end_addr, flags;
427 	unsigned long base;
428 	int i, fd;
429 
430 	/* open and read addresses of the corresponding resource in sysfs */
431 	snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource",
432 		rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
433 		dev->addr.devid, dev->addr.function);
434 	f = fopen(filename, "r");
435 	if (f == NULL) {
436 		RTE_LOG(ERR, EAL, "%s(): Cannot open sysfs resource: %s\n",
437 			__func__, strerror(errno));
438 		return -1;
439 	}
440 
441 	for (i = 0; i < bar + 1; i++) {
442 		if (fgets(buf, sizeof(buf), f) == NULL) {
443 			RTE_LOG(ERR, EAL, "%s(): Cannot read sysfs resource\n", __func__);
444 			goto error;
445 		}
446 	}
447 	if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr,
448 		&end_addr, &flags) < 0)
449 		goto error;
450 
451 	if (flags & IORESOURCE_IO) {
452 		if (rte_eal_iopl_init()) {
453 			RTE_LOG(ERR, EAL, "%s(): insufficient ioport permissions for PCI device %s\n",
454 				__func__, dev->name);
455 			goto error;
456 		}
457 
458 		base = (unsigned long)phys_addr;
459 		if (base > PIO_MAX) {
460 			RTE_LOG(ERR, EAL, "%s(): %08lx too large PIO resource\n", __func__, base);
461 			goto error;
462 		}
463 
464 		RTE_LOG(DEBUG, EAL, "%s(): PIO BAR %08lx detected\n", __func__, base);
465 	} else if (flags & IORESOURCE_MEM) {
466 		base = (unsigned long)dev->mem_resource[bar].addr;
467 		RTE_LOG(DEBUG, EAL, "%s(): MMIO BAR %08lx detected\n", __func__, base);
468 	} else {
469 		RTE_LOG(ERR, EAL, "%s(): unknown BAR type\n", __func__);
470 		goto error;
471 	}
472 
473 	/* FIXME only for primary process ? */
474 	if (rte_intr_type_get(dev->intr_handle) ==
475 					RTE_INTR_HANDLE_UNKNOWN) {
476 		int uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname), 0);
477 		if (uio_num < 0) {
478 			RTE_LOG(ERR, EAL, "cannot open %s: %s\n",
479 				dirname, strerror(errno));
480 			goto error;
481 		}
482 
483 		snprintf(filename, sizeof(filename), "/dev/uio%u", uio_num);
484 		fd = open(filename, O_RDWR);
485 		if (fd < 0) {
486 			RTE_LOG(ERR, EAL, "Cannot open %s: %s\n",
487 				filename, strerror(errno));
488 			goto error;
489 		}
490 		if (rte_intr_fd_set(dev->intr_handle, fd))
491 			goto error;
492 
493 		if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO))
494 			goto error;
495 	}
496 
497 	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%lx\n", base);
498 
499 	p->base = base;
500 	p->len = 0;
501 	fclose(f);
502 	return 0;
503 error:
504 	if (f)
505 		fclose(f);
506 	return -1;
507 }
508 #else
509 int
510 pci_uio_ioport_map(struct rte_pci_device *dev, int bar,
511 		   struct rte_pci_ioport *p)
512 {
513 	FILE *f;
514 	char buf[BUFSIZ];
515 	char filename[PATH_MAX];
516 	uint64_t phys_addr, end_addr, flags;
517 	int fd, i;
518 	void *addr;
519 
520 	/* open and read addresses of the corresponding resource in sysfs */
521 	snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource",
522 		rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
523 		dev->addr.devid, dev->addr.function);
524 	f = fopen(filename, "r");
525 	if (f == NULL) {
526 		RTE_LOG(ERR, EAL, "Cannot open sysfs resource: %s\n",
527 			strerror(errno));
528 		return -1;
529 	}
530 	for (i = 0; i < bar + 1; i++) {
531 		if (fgets(buf, sizeof(buf), f) == NULL) {
532 			RTE_LOG(ERR, EAL, "Cannot read sysfs resource\n");
533 			goto error;
534 		}
535 	}
536 	if (pci_parse_one_sysfs_resource(buf, sizeof(buf), &phys_addr,
537 			&end_addr, &flags) < 0)
538 		goto error;
539 	if ((flags & IORESOURCE_IO) == 0) {
540 		RTE_LOG(ERR, EAL, "BAR %d is not an IO resource\n", bar);
541 		goto error;
542 	}
543 	snprintf(filename, sizeof(filename), "%s/" PCI_PRI_FMT "/resource%d",
544 		rte_pci_get_sysfs_path(), dev->addr.domain, dev->addr.bus,
545 		dev->addr.devid, dev->addr.function, bar);
546 
547 	/* mmap the pci resource */
548 	fd = open(filename, O_RDWR);
549 	if (fd < 0) {
550 		RTE_LOG(ERR, EAL, "Cannot open %s: %s\n", filename,
551 			strerror(errno));
552 		goto error;
553 	}
554 	addr = mmap(NULL, end_addr + 1, PROT_READ | PROT_WRITE,
555 		MAP_SHARED, fd, 0);
556 	close(fd);
557 	if (addr == MAP_FAILED) {
558 		RTE_LOG(ERR, EAL, "Cannot mmap IO port resource: %s\n",
559 			strerror(errno));
560 		goto error;
561 	}
562 
563 	/* strangely, the base address is mmap addr + phys_addr */
564 	p->base = (uintptr_t)addr + phys_addr;
565 	p->len = end_addr + 1;
566 	RTE_LOG(DEBUG, EAL, "PCI Port IO found start=0x%"PRIx64"\n", p->base);
567 	fclose(f);
568 
569 	return 0;
570 
571 error:
572 	fclose(f);
573 	return -1;
574 }
575 #endif
576 
577 #if defined(RTE_ARCH_X86)
578 
579 static inline uint8_t ioread8(void *addr)
580 {
581 	uint8_t val;
582 
583 	val = (uint64_t)(uintptr_t)addr >= PIO_MAX ?
584 		*(volatile uint8_t *)addr :
585 #ifdef __GLIBC__
586 		inb_p((unsigned long)addr);
587 #else
588 		inb((unsigned long)addr);
589 #endif
590 
591 	return val;
592 }
593 
594 static inline uint16_t ioread16(void *addr)
595 {
596 	uint16_t val;
597 
598 	val = (uint64_t)(uintptr_t)addr >= PIO_MAX ?
599 		*(volatile uint16_t *)addr :
600 #ifdef __GLIBC__
601 		inw_p((unsigned long)addr);
602 #else
603 		inw((unsigned long)addr);
604 #endif
605 
606 	return val;
607 }
608 
609 static inline uint32_t ioread32(void *addr)
610 {
611 	uint32_t val;
612 
613 	val = (uint64_t)(uintptr_t)addr >= PIO_MAX ?
614 		*(volatile uint32_t *)addr :
615 #ifdef __GLIBC__
616 		inl_p((unsigned long)addr);
617 #else
618 		inl((unsigned long)addr);
619 #endif
620 
621 	return val;
622 }
623 
624 static inline void iowrite8(uint8_t val, void *addr)
625 {
626 	(uint64_t)(uintptr_t)addr >= PIO_MAX ?
627 		*(volatile uint8_t *)addr = val :
628 #ifdef __GLIBC__
629 		outb_p(val, (unsigned long)addr);
630 #else
631 		outb(val, (unsigned long)addr);
632 #endif
633 }
634 
635 static inline void iowrite16(uint16_t val, void *addr)
636 {
637 	(uint64_t)(uintptr_t)addr >= PIO_MAX ?
638 		*(volatile uint16_t *)addr = val :
639 #ifdef __GLIBC__
640 		outw_p(val, (unsigned long)addr);
641 #else
642 		outw(val, (unsigned long)addr);
643 #endif
644 }
645 
646 static inline void iowrite32(uint32_t val, void *addr)
647 {
648 	(uint64_t)(uintptr_t)addr >= PIO_MAX ?
649 		*(volatile uint32_t *)addr = val :
650 #ifdef __GLIBC__
651 		outl_p(val, (unsigned long)addr);
652 #else
653 		outl(val, (unsigned long)addr);
654 #endif
655 }
656 
657 #else /* !RTE_ARCH_X86 */
658 
659 static inline uint8_t ioread8(void *addr)
660 {
661 	return *(volatile uint8_t *)addr;
662 }
663 
664 static inline uint16_t ioread16(void *addr)
665 {
666 	return *(volatile uint16_t *)addr;
667 }
668 
669 static inline uint32_t ioread32(void *addr)
670 {
671 	return *(volatile uint32_t *)addr;
672 }
673 
674 static inline void iowrite8(uint8_t val, void *addr)
675 {
676 	*(volatile uint8_t *)addr = val;
677 }
678 
679 static inline void iowrite16(uint16_t val, void *addr)
680 {
681 	*(volatile uint16_t *)addr = val;
682 }
683 
684 static inline void iowrite32(uint32_t val, void *addr)
685 {
686 	*(volatile uint32_t *)addr = val;
687 }
688 
689 #endif /* !RTE_ARCH_X86 */
690 
691 void
692 pci_uio_ioport_read(struct rte_pci_ioport *p,
693 		    void *data, size_t len, off_t offset)
694 {
695 	uint8_t *d;
696 	int size;
697 	uintptr_t reg = p->base + offset;
698 
699 	for (d = data; len > 0; d += size, reg += size, len -= size) {
700 		if (len >= 4) {
701 			size = 4;
702 			*(uint32_t *)d = ioread32((void *)reg);
703 		} else if (len >= 2) {
704 			size = 2;
705 			*(uint16_t *)d = ioread16((void *)reg);
706 		} else {
707 			size = 1;
708 			*d = ioread8((void *)reg);
709 		}
710 	}
711 }
712 
713 void
714 pci_uio_ioport_write(struct rte_pci_ioport *p,
715 		     const void *data, size_t len, off_t offset)
716 {
717 	const uint8_t *s;
718 	int size;
719 	uintptr_t reg = p->base + offset;
720 
721 	for (s = data; len > 0; s += size, reg += size, len -= size) {
722 		if (len >= 4) {
723 			size = 4;
724 			iowrite32(*(const uint32_t *)s, (void *)reg);
725 		} else if (len >= 2) {
726 			size = 2;
727 			iowrite16(*(const uint16_t *)s, (void *)reg);
728 		} else {
729 			size = 1;
730 			iowrite8(*s, (void *)reg);
731 		}
732 	}
733 }
734 
735 int
736 pci_uio_ioport_unmap(struct rte_pci_ioport *p)
737 {
738 #if defined(RTE_ARCH_X86)
739 	RTE_SET_USED(p);
740 	/* FIXME close intr fd ? */
741 	return 0;
742 #else
743 	return munmap((void *)(uintptr_t)p->base, p->len);
744 #endif
745 }
746