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