Exemplo n.º 1
0
static const struct odp_mm_district *mm_district_reserve_aligned(
	const char *name, const char *orig_name,
	size_t len,
	int socket_id, unsigned flags,
	unsigned align,
	unsigned bound)
{
	struct odp_sys_layout *mcfg;
	unsigned i = 0;
	int mmfrag_idx = -1;
	uint64_t addr_offset, seg_offset = 0;
	size_t	 requested_len;
	size_t	 mmfrag_len = 0;
	phys_addr_t mmfrag_physaddr;
	void *mmfrag_addr;
	struct odp_mm_district *md = NULL;

	/* get pointer to global configuration */
	mcfg = odp_get_configuration()->sys_layout;

	/* no more room in config */
	if (mcfg->mm_district_idx >= ODP_MAX_MM_DISTRICT) {
		ODP_ERR("%s: No more room in config\n", name);
		odp_err = ENOSPC;
		return NULL;
	}

	/* zone already exist */
	if (mm_district_lookup(name)) {
		ODP_ERR("mm_district <%s> already exists\n", name);
		odp_err = EEXIST;
		return NULL;
	}

	if (!orig_name) {
		ODP_ERR("Invalid param: orig_name\n");
		odp_err = EINVAL;
		return NULL;
	}

	md = free_mm_district_lookup(orig_name);
	if (md)
		if (len <= md->len) {
			free_mm_district_fetch(md);
			return md;
		}

	/* if alignment is not a power of two */
	if (align && !odp_is_power_of_2(align)) {
		ODP_ERR("Invalid alignment: %u\n", align);
		odp_err = EINVAL;
		return NULL;
	}

	/* alignment less than cache size is not allowed */
	if (align < ODP_CACHE_LINE_SIZE)
		align = ODP_CACHE_LINE_SIZE;

	/* align length on cache boundary. Check for overflow before doing so */
	if (len > MEM_SIZE_MAX - ODP_CACHE_LINE_MASK) {
		odp_err = EINVAL; /* requested size too big */
		return NULL;
	}

	len += ODP_CACHE_LINE_MASK;
	len &= ~((size_t)ODP_CACHE_LINE_MASK);

	/* save minimal requested  length */
	requested_len = ODP_MAX((size_t)ODP_CACHE_LINE_SIZE, len);

	/* check that boundary condition is valid */
	if ((bound != 0) && ((requested_len > bound) ||
			     !odp_is_power_of_2(bound))) {
		odp_err = EINVAL;
		return NULL;
	}

	/* find the smallest segment matching requirements */
	for (i = 0; i < ODP_MAX_MMFRAG; i++) {
		/* last segment */
		if (!free_mmfrag[i].addr)
			break;

		/* empty segment, skip it */
		if (free_mmfrag[i].len == 0)
			continue;

		/* bad socket ID */
		if ((socket_id != SOCKET_ID_ANY) &&
		    (free_mmfrag[i].socket_id != SOCKET_ID_ANY) &&
		    (socket_id != free_mmfrag[i].socket_id))
			continue;

		/*
		 * calculate offset to closest alignment that
		 * meets boundary conditions.
		 */
		addr_offset = align_phys_boundary(free_mmfrag + i,
						  requested_len, align, bound);

		/* check len */
		if ((requested_len + addr_offset) > free_mmfrag[i].len)
			continue;

		/* check flags for hugepage sizes */
		if ((flags & ODP_MEMZONE_2MB) &&
		    (free_mmfrag[i].hugepage_sz == ODP_PGSIZE_1G))
			continue;

		if ((flags & ODP_MEMZONE_1GB) &&
		    (free_mmfrag[i].hugepage_sz == ODP_PGSIZE_2M))
			continue;

		if ((flags & ODP_MEMZONE_16MB) &&
		    (free_mmfrag[i].hugepage_sz == ODP_PGSIZE_16G))
			continue;

		if ((flags & ODP_MEMZONE_16GB) &&
		    (free_mmfrag[i].hugepage_sz == ODP_PGSIZE_16M))
			continue;

		/* this segment is the best until now */
		if (mmfrag_idx == -1) {
			mmfrag_idx = i;
			mmfrag_len = free_mmfrag[i].len;
			seg_offset = addr_offset;
		}

		/* find the biggest contiguous zone */
		else if (len == 0) {
			if (free_mmfrag[i].len > mmfrag_len) {
				mmfrag_idx = i;
				mmfrag_len = free_mmfrag[i].len;
				seg_offset = addr_offset;
			}
		}

		/*
		 * find the smallest (we already checked that current
		 * zone length is > len
		 */
		else if ((free_mmfrag[i].len + align < mmfrag_len) ||
			 ((free_mmfrag[i].len <= mmfrag_len + align) &&
			  (addr_offset < seg_offset))) {
			mmfrag_idx = i;
			mmfrag_len = free_mmfrag[i].len;
			seg_offset = addr_offset;
		}
	}

	/* no segment found */
	if (mmfrag_idx == -1) {
		/*
		 * If ODP_MEMZONE_SIZE_HINT_ONLY flag is specified,
		 * try allocating again without the size parameter
		 * otherwise -fail.
		 */
		if ((flags & ODP_MEMZONE_SIZE_HINT_ONLY) &&
		    ((flags & ODP_MEMZONE_1GB) ||
		     (flags & ODP_MEMZONE_2MB) ||
		     (flags & ODP_MEMZONE_16MB) ||
		     (flags & ODP_MEMZONE_16GB)))
			return mm_district_reserve_aligned(name, orig_name,
							   len, socket_id, 0,
							   align, bound);

		odp_err = ENOMEM;
		return NULL;
	}

	/* save aligned physical and virtual addresses */
	mmfrag_physaddr = free_mmfrag[mmfrag_idx].phys_addr + seg_offset;
	mmfrag_addr = ODP_PTR_ADD(free_mmfrag[mmfrag_idx].addr,
				  (uintptr_t)seg_offset);

	/* if we are looking for a biggest mm_district */
	if (len == 0) {
		if (bound == 0)
			requested_len = mmfrag_len - seg_offset;
		else
			requested_len =
				ODP_ALIGN_CEIL(mmfrag_physaddr + 1, bound)
				- mmfrag_physaddr;
	}

	/* set length to correct value */
	len = (size_t)seg_offset + requested_len;

	/* update our internal state */
	free_mmfrag[mmfrag_idx].len -= len;
	free_mmfrag[mmfrag_idx].phys_addr += len;
	free_mmfrag[mmfrag_idx].addr =
		(char *)free_mmfrag[mmfrag_idx].addr + len;

	/* fill the zone in config */
	struct odp_mm_district *mz =
		&mcfg->mm_district[mcfg->mm_district_idx++];

	snprintf(mz->orig_name, sizeof(mz->orig_name), "%s", orig_name);
	snprintf(mz->name, sizeof(mz->name), "%s", name);
	mz->phys_addr = mmfrag_physaddr;
	mz->phys_addr_end  = mmfrag_physaddr + requested_len;
	mz->excursion_addr = mmfrag_addr - mmfrag_physaddr;
	mz->addr = mmfrag_addr;
	mz->len	 = requested_len;
	mz->hugepage_sz = free_mmfrag[mmfrag_idx].hugepage_sz;
	mz->socket_id = free_mmfrag[mmfrag_idx].socket_id;
	mz->flags = 0;
	mz->mmfrag_id = mmfrag_idx;

	return mz;
}
Exemplo n.º 2
0
/* 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;
}