/* unmap the PCI resource of a PCI device in virtual memory */ void pci_uio_unmap_resource(struct odp_pci_device *dev) { struct mapped_pci_resource *uio_res; struct mapped_pci_res_list *uio_res_list = ODP_TAILQ_CAST(odp_uio_tailq.head, mapped_pci_res_list); if (!dev) return; /* find an entry for the device */ uio_res = pci_uio_find_resource(dev); if (!uio_res) return; /* secondary processes - just free maps */ if (odp_process_type() != ODP_PROC_PRIMARY) return pci_uio_unmap(uio_res); TAILQ_REMOVE(uio_res_list, uio_res, next); /* unmap all resources */ pci_uio_unmap(uio_res); /* free uio resource */ free(uio_res); /* close fd if in primary process */ close(dev->intr_handle.fd); dev->intr_handle.fd = -1; dev->intr_handle.type = ODP_INTR_HANDLE_UNKNOWN; }
/* create the ring */ struct odp_ring *odp_ring_create(const char *name, unsigned count, int socket_id, unsigned flags) { char mz_name[ODP_MEMZONE_NAMESIZE]; struct odp_ring *r; struct odp_tailq_entry *te; const struct odp_mm_district *mz; ssize_t ring_size; int mz_flags = 0; struct odp_ring_list *ring_list = NULL; ring_list = ODP_TAILQ_CAST(odp_ring_tailq.head, odp_ring_list); ring_size = odp_ring_get_memsize(count); if (ring_size < 0) { odp_err = ring_size; return NULL; } te = malloc(sizeof(*te)); if (te == NULL) { ODP_PRINT("Cannot reserve memory for tailq\n"); odp_err = ENOMEM; return NULL; } snprintf(mz_name, sizeof(mz_name), "%s%s", ODP_RING_MZ_PREFIX, name); odp_rwlock_write_lock(ODP_TAILQ_RWLOCK); /* reserve a memory zone for this ring. If we can't get odp_config or * we are secondary process, the mm_district_reserve function will set * odp_err for us appropriately-hence no check in this this function */ mz = odp_mm_district_reserve(mz_name, mz_name, ring_size, socket_id, mz_flags); if (mz != NULL) { r = mz->addr; /* no need to check return value here, we already checked the * arguments above */ odp_ring_init(r, name, count, flags); te->data = (void *)r; TAILQ_INSERT_TAIL(ring_list, te, next); } else { r = NULL; ODP_PRINT("Cannot reserve memory\n"); free(te); } odp_rwlock_write_unlock(ODP_TAILQ_RWLOCK); return r; }
/* dump the status of all rings on the console */ void odp_ring_list_dump(FILE *f) { const struct odp_tailq_entry *te; struct odp_ring_list *ring_list; ring_list = ODP_TAILQ_CAST(odp_ring_tailq.head, odp_ring_list); odp_rwlock_read_lock(ODP_TAILQ_RWLOCK); TAILQ_FOREACH(te, ring_list, next) { odp_ring_dump(f, (struct odp_ring *)te->data); }
static int pci_uio_map_secondary(struct odp_pci_device *dev) { int fd, i; struct mapped_pci_resource *uio_res; struct mapped_pci_res_list *uio_res_list = ODP_TAILQ_CAST(odp_uio_tailq.head, mapped_pci_res_list); TAILQ_FOREACH(uio_res, uio_res_list, next) { /* skip this element if it doesn't match our PCI address */ if (odp_compare_pci_addr(&uio_res->pci_addr, &dev->addr)) continue; for (i = 0; i != uio_res->nb_maps; i++) { /* * open devname, to mmap it */ fd = open(uio_res->maps[i].path, O_RDWR); if (fd < 0) { PRINT("Cannot open %s: %s\n", uio_res->maps[i].path, strerror(errno)); return -1; } void *mapaddr = pci_map_resource(uio_res->maps[i].addr, fd, (off_t)uio_res->maps[i].offset, (size_t)uio_res->maps[i].size, 0); if (mapaddr != uio_res->maps[i].addr) { if (mapaddr == MAP_FAILED) PRINT("Cannot mmap device resource file %s: %s\n", uio_res->maps[i].path, strerror(errno)); else PRINT("Cannot mmap device resource file %s to address: %p\n", uio_res->maps[i].path, uio_res->maps[i].addr); close(fd); return -1; } /* fd is not needed in slave process, close it */ close(fd); } return 0; } PRINT("Cannot find resource for device\n"); return 1; }
static struct mapped_pci_resource *pci_uio_find_resource(struct odp_pci_device *dev) { struct mapped_pci_resource *uio_res; struct mapped_pci_res_list *uio_res_list = ODP_TAILQ_CAST(odp_uio_tailq.head, mapped_pci_res_list); if (!dev) return NULL; TAILQ_FOREACH(uio_res, uio_res_list, next) { /* skip this element if it doesn't match our PCI address */ if (!odp_compare_pci_addr(&uio_res->pci_addr, &dev->addr)) return uio_res; } return NULL; }
/* map the PCI resource of a PCI device in virtual memory */ int pci_uio_map_resource(struct odp_pci_device *dev) { int i, map_idx; char dirname[ODP_PATH_MAX]; char cfgname[ODP_PATH_MAX]; char devname[ODP_PATH_MAX]; /* contains the /dev/uioX */ void *mapaddr; int uio_num; uint64_t phaddr; struct odp_pci_addr *loc = &dev->addr; struct mapped_pci_resource *uio_res; struct mapped_pci_res_list *uio_res_list = ODP_TAILQ_CAST(odp_uio_tailq.head, mapped_pci_res_list); struct pci_map *maps; dev->intr_handle.fd = -1; dev->intr_handle.uio_cfg_fd = -1; dev->intr_handle.type = ODP_INTR_HANDLE_UNKNOWN; /* secondary processes - use already recorded details */ if (odp_process_type() != ODP_PROC_PRIMARY) return pci_uio_map_secondary(dev); /* find uio resource */ uio_num = pci_get_uio_dev(dev, dirname, sizeof(dirname)); if (uio_num < 0) { PRINT(" " PCI_PRI_FMT " not managed by UIO driver, skipping\n", loc->domain, loc->bus, loc->devid, loc->function); return 1; } snprintf(devname, sizeof(devname), "/dev/uio%u", uio_num); /* save fd if in primary process */ dev->intr_handle.fd = open(devname, O_RDWR); if (dev->intr_handle.fd < 0) { PRINT("Cannot open %s: %s\n", devname, strerror(errno)); return -1; } dev->intr_handle.type = ODP_INTR_HANDLE_UIO; snprintf(cfgname, sizeof(cfgname), "/sys/class/uio/uio%u/device/config", uio_num); dev->intr_handle.uio_cfg_fd = open(cfgname, O_RDWR); if (dev->intr_handle.uio_cfg_fd < 0) { PRINT("Cannot open %s: %s\n", cfgname, strerror(errno)); return -1; } /* set bus master that is not done by uio_pci_generic */ if (pci_uio_set_bus_master(dev->intr_handle.uio_cfg_fd)) { PRINT("Cannot set up bus mastering!\n"); return -1; } /* allocate the mapping details for secondary processes*/ uio_res = malloc(sizeof(*uio_res)); if (!uio_res) { PRINT("%s(): cannot store uio mmap details\n", __func__); return -1; } snprintf(uio_res->path, sizeof(uio_res->path), "%s", devname); memcpy(&uio_res->pci_addr, &dev->addr, sizeof(uio_res->pci_addr)); /* Map all BARs */ maps = uio_res->maps; for (i = 0, map_idx = 0; i != PCI_MAX_RESOURCE; i++) { int fd; int fail = 0; /* skip empty BAR */ phaddr = dev->mem_resource[i].phys_addr; if (phaddr == 0) continue; /* update devname for mmap */ snprintf(devname, sizeof(devname), SYSFS_PCI_DEVICES "/" PCI_PRI_FMT "/resource%d", loc->domain, loc->bus, loc->devid, loc->function, i); /* * open resource file, to mmap it */ fd = open(devname, O_RDWR); if (fd < 0) { PRINT("Cannot open %s: %s\n", devname, strerror(errno)); return -1; } /* try mapping somewhere close to the end of hugepages */ if (!pci_map_addr) pci_map_addr = pci_find_max_end_va(); mapaddr = pci_map_resource(pci_map_addr, fd, 0, (size_t)dev->mem_resource[i].len, 0); if (mapaddr == MAP_FAILED) fail = 1; pci_map_addr = ODP_PTR_ADD(mapaddr, (size_t)dev->mem_resource[i].len); maps[map_idx].path = malloc(strlen(devname) + 1); if (!maps[map_idx].path) fail = 1; if (fail) { free(uio_res); close(fd); return -1; } close(fd); maps[map_idx].phaddr = dev->mem_resource[i].phys_addr; maps[map_idx].size = dev->mem_resource[i].len; maps[map_idx].addr = mapaddr; maps[map_idx].offset = 0; strcpy(maps[map_idx].path, devname); map_idx++; dev->mem_resource[i].addr = mapaddr; } uio_res->nb_maps = map_idx; TAILQ_INSERT_TAIL(uio_res_list, uio_res, next); return 0; }