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