Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09d27a06 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "iommu/io-pgtable-arm: support querying IOVA coherency"

parents 8787746e f18f48d7
Loading
Loading
Loading
Loading
+66 −12
Original line number Diff line number Diff line
@@ -109,6 +109,7 @@
#define ARM_LPAE_PTE_AP_RW		(((arm_lpae_iopte)1) << 6)
#define ARM_LPAE_PTE_AP_PRIV_RO		(((arm_lpae_iopte)2) << 6)
#define ARM_LPAE_PTE_AP_RO		(((arm_lpae_iopte)3) << 6)
#define ARM_LPAE_PTE_ATTRINDX_MASK	0x7
#define ARM_LPAE_PTE_ATTRINDX_SHIFT	2
#define ARM_LPAE_PTE_nG			(((arm_lpae_iopte)1) << 11)

@@ -813,39 +814,91 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
	return unmapped;
}

static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
					 unsigned long iova)
static int arm_lpae_iova_to_pte(struct arm_lpae_io_pgtable *data,
				unsigned long iova, int *plvl_ret,
				arm_lpae_iopte *ptep_ret)
{
	struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
	arm_lpae_iopte pte, *ptep = data->pgd;
	int lvl = ARM_LPAE_START_LVL(data);
	*plvl_ret = ARM_LPAE_START_LVL(data);
	*ptep_ret = 0;

	do {
		/* Valid IOPTE pointer? */
		if (!ptep)
			return 0;
			return -EINVAL;

		/* Grab the IOPTE we're interested in */
		pte = *(ptep + ARM_LPAE_LVL_IDX(iova, lvl, data));
		pte = *(ptep + ARM_LPAE_LVL_IDX(iova, *plvl_ret, data));

		/* Valid entry? */
		if (!pte)
			return 0;
			return -EINVAL;

		/* Leaf entry? */
		if (iopte_leaf(pte,lvl))
		if (iopte_leaf(pte, *plvl_ret))
			goto found_translation;

		/* Take it to the next level */
		ptep = iopte_deref(pte, data);
	} while (++lvl < ARM_LPAE_MAX_LEVELS);
	} while (++(*plvl_ret) < ARM_LPAE_MAX_LEVELS);

	/* Ran out of page tables to walk */
	return 0;
	return -EINVAL;

found_translation:
	*ptep_ret = pte;
	return 0;
}

static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
					 unsigned long iova)
{
	struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
	arm_lpae_iopte pte;
	int lvl;
	phys_addr_t phys = 0;

	if (!arm_lpae_iova_to_pte(data, iova, &lvl, &pte)) {
		iova &= ((1 << ARM_LPAE_LVL_SHIFT(lvl, data)) - 1);
	return ((phys_addr_t)iopte_to_pfn(pte,data) << data->pg_shift) | iova;
		phys = ((phys_addr_t)iopte_to_pfn(pte, data)
				<< data->pg_shift) | iova;
	}

	return phys;
}

static bool __arm_lpae_is_iova_coherent(struct arm_lpae_io_pgtable *data,
				    arm_lpae_iopte *ptep)
{
	if (data->iop.fmt == ARM_64_LPAE_S1 ||
	    data->iop.fmt == ARM_32_LPAE_S1) {
		int attr_idx = (*ptep & (ARM_LPAE_PTE_ATTRINDX_MASK <<
					ARM_LPAE_PTE_ATTRINDX_SHIFT)) >>
					ARM_LPAE_PTE_ATTRINDX_SHIFT;
		if ((attr_idx == ARM_LPAE_MAIR_ATTR_IDX_CACHE) &&
		    ((*ptep & ARM_LPAE_PTE_SH_IS) ||
		     (*ptep & ARM_LPAE_PTE_SH_OS)))
			return true;
	} else {
		if (*ptep & ARM_LPAE_PTE_MEMATTR_OIWB)
			return true;
	}

	return false;
}

static bool arm_lpae_is_iova_coherent(struct io_pgtable_ops *ops,
					 unsigned long iova)
{
	struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
	arm_lpae_iopte pte;
	int lvl;
	bool ret = false;

	if (!arm_lpae_iova_to_pte(data, iova, &lvl, &pte))
		ret = __arm_lpae_is_iova_coherent(data, &pte);

	return ret;
}

static void arm_lpae_restrict_pgsizes(struct io_pgtable_cfg *cfg)
@@ -925,6 +978,7 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg)
		.map_sg		= arm_lpae_map_sg,
		.unmap		= arm_lpae_unmap,
		.iova_to_phys	= arm_lpae_iova_to_phys,
		.is_iova_coherent = arm_lpae_is_iova_coherent,
	};

	return data;
+3 −0
Original line number Diff line number Diff line
@@ -114,6 +114,9 @@ struct io_pgtable_ops {
			size_t size);
	phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops,
				    unsigned long iova);
	bool (*is_iova_coherent)(struct io_pgtable_ops *ops,
				unsigned long iova);

};

/**