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

Commit 4d7cdd9e authored by Rohit Vaswani's avatar Rohit Vaswani Committed by Patrick Daly
Browse files

iommu/arm-smmu: Check the return type of map_sg and take appropriate action



We cannot call unmap directly if the map_sg fails partially as the tlb
invalidate functions need to enable/prepare clocks, which require
non-atomic context. Let map_sg return the failure and handle this when
we are out of the atomic context.

Change-Id: I6401c1e281850aeda27e32524cae34324045f762
Signed-off-by: default avatarRohit Vaswani <rvaswani@codeaurora.org>
Signed-off-by: default avatarPatrick Daly <pdaly@codeaurora.org>
parent daab041f
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -1606,6 +1606,7 @@ static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova,
			   struct scatterlist *sg, unsigned int nents, int prot)
{
	int ret;
	size_t size;
	unsigned long flags;
	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
	struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops;
@@ -1614,8 +1615,12 @@ static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova,
		return -ENODEV;

	spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
	ret = ops->map_sg(ops, iova, sg, nents, prot);
	ret = ops->map_sg(ops, iova, sg, nents, prot, &size);
	spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);

	if (!ret)
		arm_smmu_unmap(domain, iova, size);

	return ret;
}

+4 −6
Original line number Diff line number Diff line
@@ -407,7 +407,7 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova,

static int arm_lpae_map_sg(struct io_pgtable_ops *ops, unsigned long iova,
			   struct scatterlist *sg, unsigned int nents,
			   int iommu_prot)
			   int iommu_prot, size_t *size)
{
	struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
	arm_lpae_iopte *ptep = data->pgd;
@@ -420,7 +420,7 @@ static int arm_lpae_map_sg(struct io_pgtable_ops *ops, unsigned long iova,

	/* If no access, then nothing to do */
	if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
		return 0;
		goto out_err;

	prot = arm_lpae_prot_to_pte(data, iommu_prot);

@@ -457,10 +457,8 @@ static int arm_lpae_map_sg(struct io_pgtable_ops *ops, unsigned long iova,
	return mapped;

out_err:
	/* undo mappings already done */
	if (mapped)
		ops->unmap(ops, iova, mapped);

	/* Return the size of the partial mapping so that they can be undone */
	*size = mapped;
	return 0;
}

+4 −1
Original line number Diff line number Diff line
@@ -105,6 +105,8 @@ struct io_pgtable_cfg {
 * struct io_pgtable_ops - Page table manipulation API for IOMMU drivers.
 *
 * @map:          Map a physically contiguous memory region.
 * @map_sg:	  Map a scatterlist. The size parameter contains the size
 *		  of the partial mapping in case of failure.
 * @unmap:        Unmap a physically contiguous memory region.
 * @iova_to_phys: Translate iova to physical address.
 *
@@ -115,7 +117,8 @@ struct io_pgtable_ops {
	int (*map)(struct io_pgtable_ops *ops, unsigned long iova,
		   phys_addr_t paddr, size_t size, int prot);
	int (*map_sg)(struct io_pgtable_ops *ops, unsigned long iova,
		      struct scatterlist *sg, unsigned int nents, int prot);
		      struct scatterlist *sg, unsigned int nents,
		      int prot, size_t *size);
	int (*unmap)(struct io_pgtable_ops *ops, unsigned long iova,
		     size_t size);
	phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops,