Example #1
0
static int __arm_lpae_map(struct arm_lpae_io_pgtable *data,
			  physical_addr_t iova,
			  physical_addr_t paddr,
			  size_t size,
			  arm_lpae_iopte prot,
			  int lvl, arm_lpae_iopte *ptep)
{
	int rc;
	physical_addr_t pa;
	arm_lpae_iopte *cptep, pte;
	size_t block_size = ARM_LPAE_BLOCK_SIZE(lvl, data);
	struct io_pgtable_cfg *cfg = &data->iop.cfg;

	/* Find our entry at the current level */
	ptep += ARM_LPAE_LVL_IDX(iova, lvl, data);

	/* If we can install a leaf entry at this level, then do so */
	if (size == block_size && (size & cfg->pgsize_bitmap))
		return arm_lpae_init_pte(data, iova, paddr, prot, lvl, ptep);

	/* We can't allocate tables at the final level */
	if (WARN_ON(lvl >= ARM_LPAE_MAX_LEVELS - 1))
		return VMM_EINVALID;

	/* Grab a pointer to the next level */
	pte = *ptep;
	if (!pte) {
		cptep = __arm_lpae_alloc_pages(ARM_LPAE_GRANULE(data),
					       cfg);
		if (!cptep)
			return VMM_ENOMEM;

		rc = vmm_host_va2pa((virtual_addr_t)cptep, &pa);
		if (rc)
			return rc;

		pte = pa | ARM_LPAE_PTE_TYPE_TABLE;
		if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS)
			pte |= ARM_LPAE_PTE_NSTABLE;
		__arm_lpae_set_pte(ptep, pte, cfg);
	} else {
		cptep = iopte_deref(pte, data);
	}

	/* Rinse, repeat */
	return __arm_lpae_map(data, iova, paddr, size, prot, lvl + 1, cptep);
}
Example #2
0
static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
			  phys_addr_t paddr, size_t size, arm_lpae_iopte prot,
			  int lvl, arm_lpae_iopte *ptep)
{
	arm_lpae_iopte *cptep, pte;
	size_t block_size = ARM_LPAE_BLOCK_SIZE(lvl, data);
	struct io_pgtable_cfg *cfg = &data->iop.cfg;

	/* Find our entry at the current level */
	ptep += ARM_LPAE_LVL_IDX(iova, lvl, data);

	/* If we can install a leaf entry at this level, then do so */
	if (size == block_size && (size & cfg->pgsize_bitmap))
		return arm_lpae_init_pte(data, iova, paddr, prot, lvl, ptep);

	/* We can't allocate tables at the final level */
	if (WARN_ON(lvl >= ARM_LPAE_MAX_LEVELS - 1))
		return -EINVAL;

	/* Grab a pointer to the next level */
	pte = *ptep;
	if (!pte) {
		cptep = __arm_lpae_alloc_pages(ARM_LPAE_GRANULE(data),
					       GFP_ATOMIC, cfg);
		if (!cptep)
			return -ENOMEM;

		pte = __pa(cptep) | ARM_LPAE_PTE_TYPE_TABLE;
		if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS)
			pte |= ARM_LPAE_PTE_NSTABLE;
		__arm_lpae_set_pte(ptep, pte, cfg);
	} else if (!iopte_leaf(pte, lvl)) {
		cptep = iopte_deref(pte, data);
	} else {
		/* We require an unmap first */
		WARN_ON(!selftest_running);
		return -EEXIST;
	}

	/* Rinse, repeat */
	return __arm_lpae_map(data, iova, paddr, size, prot, lvl + 1, cptep);
}