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