static int pci_device_freebsd_unmap_range( struct pci_device *dev, struct pci_device_mapping *map ) { struct mem_range_desc mrd; struct mem_range_op mro; int fd; if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) || (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) { fd = open("/dev/mem", O_RDWR | O_CLOEXEC); if (fd != -1) { mrd.mr_base = map->base; mrd.mr_len = map->size; strncpy(mrd.mr_owner, "pciaccess", sizeof(mrd.mr_owner)); mrd.mr_flags = MDF_UNCACHEABLE; mro.mo_desc = &mrd; mro.mo_arg[0] = MEMRANGE_SET_REMOVE; if (ioctl(fd, MEMRANGE_SET, &mro)) { fprintf(stderr, "failed to unset mtrr: %s\n", strerror(errno)); } close(fd); } else { fprintf(stderr, "Failed to open /dev/mem\n"); } } return pci_device_generic_unmap_range(dev, map); }
static int pci_device_openbsd_unmap_range(struct pci_device *dev, struct pci_device_mapping *map) { #if defined(__i386__) || defined(__amd64__) struct mem_range_desc mr; struct mem_range_op mo; if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) || (map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE)) { mr.mr_base = map->base; mr.mr_len = map->size; mr.mr_flags = MDF_UNCACHEABLE; strlcpy(mr.mr_owner, "pciaccess", sizeof(mr.mr_owner)); mo.mo_desc = &mr; mo.mo_arg[0] = MEMRANGE_SET_REMOVE; (void)ioctl(aperturefd, MEMRANGE_SET, &mo); } #endif return pci_device_generic_unmap_range(dev, map); }
/** * Map a memory region for a device using the Linux sysfs interface. * * \param dev Device whose memory region is to be mapped. * \param map Parameters of the mapping that is to be created. * * \return * Zero on success or an \c errno value on failure. * * \sa pci_device_map_rrange, pci_device_linux_sysfs_unmap_range * * \todo * Some older 2.6.x kernels don't implement the resourceN files. On those * systems /dev/mem must be used. On these systems it is also possible that * \c mmap64 may need to be used. */ static int pci_device_linux_sysfs_map_range(struct pci_device *dev, struct pci_device_mapping *map) { char name[256]; int fd; int err = 0; const int prot = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) ? (PROT_READ | PROT_WRITE) : PROT_READ; const int open_flags = ((map->flags & PCI_DEV_MAP_FLAG_WRITABLE) != 0) ? O_RDWR : O_RDONLY; const off_t offset = map->base - dev->regions[map->region].base_addr; #ifdef HAVE_MTRR struct mtrr_sentry sentry = { .base = map->base, .size = map->size, .type = MTRR_TYPE_UNCACHABLE }; #endif /* For WC mappings, try sysfs resourceN_wc file first */ if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) && !pci_device_linux_sysfs_map_range_wc(dev, map)) return 0; snprintf(name, 255, "%s/%04x:%02x:%02x.%1u/resource%u", SYS_BUS_PCI, dev->domain, dev->bus, dev->dev, dev->func, map->region); fd = open(name, open_flags | O_CLOEXEC); if (fd == -1) { return errno; } map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset); if (map->memory == MAP_FAILED) { map->memory = NULL; close(fd); return errno; } #ifdef HAVE_MTRR if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) != 0) { sentry.type = MTRR_TYPE_WRBACK; } else if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) != 0) { sentry.type = MTRR_TYPE_WRCOMB; } if (pci_sys->mtrr_fd != -1 && sentry.type != MTRR_TYPE_UNCACHABLE) { if (ioctl(pci_sys->mtrr_fd, MTRRIOC_ADD_ENTRY, &sentry) < 0) { /* FIXME: Should we report an error in this case? */ fprintf(stderr, "error setting MTRR " "(base = 0x%08lx, size = 0x%08x, type = %u) %s (%d)\n", sentry.base, sentry.size, sentry.type, strerror(errno), errno); /* err = errno;*/ } /* KLUDGE ALERT -- rewrite the PTEs to turn off the CD and WT bits */ mprotect (map->memory, map->size, PROT_NONE); err = mprotect (map->memory, map->size, PROT_READ|PROT_WRITE); if (err != 0) { fprintf(stderr, "mprotect(PROT_READ | PROT_WRITE) failed: %s\n", strerror(errno)); fprintf(stderr, "remapping without mprotect performance kludge.\n"); munmap(map->memory, map->size); map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset); if (map->memory == MAP_FAILED) { map->memory = NULL; close(fd); return errno; } } } #endif close(fd); return 0; } /** * Unmap a memory region for a device using the Linux sysfs interface. * * \param dev Device whose memory region is to be unmapped. * \param map Parameters of the mapping that is to be destroyed. * * \return * Zero on success or an \c errno value on failure. * * \sa pci_device_map_rrange, pci_device_linux_sysfs_map_range * * \todo * Some older 2.6.x kernels don't implement the resourceN files. On those * systems /dev/mem must be used. On these systems it is also possible that * \c mmap64 may need to be used. */ static int pci_device_linux_sysfs_unmap_range(struct pci_device *dev, struct pci_device_mapping *map) { int err = 0; #ifdef HAVE_MTRR struct mtrr_sentry sentry = { .base = map->base, .size = map->size, .type = MTRR_TYPE_UNCACHABLE }; #endif err = pci_device_generic_unmap_range (dev, map); if (err) return err; #ifdef HAVE_MTRR if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) != 0) { sentry.type = MTRR_TYPE_WRBACK; } else if ((map->flags & PCI_DEV_MAP_FLAG_WRITE_COMBINE) != 0) { sentry.type = MTRR_TYPE_WRCOMB; } if (pci_sys->mtrr_fd != -1 && sentry.type != MTRR_TYPE_UNCACHABLE) { if (ioctl(pci_sys->mtrr_fd, MTRRIOC_DEL_ENTRY, &sentry) < 0) { /* FIXME: Should we report an error in this case? */ fprintf(stderr, "error setting MTRR " "(base = 0x%08lx, size = 0x%08x, type = %u) %s (%d)\n", sentry.base, sentry.size, sentry.type, strerror(errno), errno); /* err = errno;*/ } } #endif return err; } static void pci_device_linux_sysfs_enable(struct pci_device *dev) { char name[256]; int fd; snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/enable", SYS_BUS_PCI, dev->domain, dev->bus, dev->dev, dev->func ); fd = open( name, O_RDWR | O_CLOEXEC); if (fd == -1) return; write( fd, "1", 1 ); close(fd); }