diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index d23eee55e384..24a057dfbc2f 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -3103,8 +3103,13 @@ static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova, idx_end - idx_start, prot, &size); spin_unlock_irqrestore(&smmu_domain->cb_lock, flags); - if (ret == -ENOMEM) { + /* unmap any partially mapped iova */ + if (size) { + arm_smmu_secure_domain_unlock(smmu_domain); + arm_smmu_unmap(domain, iova, size, NULL); + arm_smmu_secure_domain_lock(smmu_domain); + } arm_smmu_prealloc_memory(smmu_domain, batch_size, &nonsecure_pool); spin_lock_irqsave(&smmu_domain->cb_lock, flags); @@ -3120,8 +3125,8 @@ static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova, &nonsecure_pool); } - /* Returns 0 on error */ - if (!ret) { + /* Returns -ve val on error */ + if (ret < 0) { size_to_unmap = iova + size - __saved_iova_start; goto out; } @@ -3129,6 +3134,7 @@ static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova, iova += batch_size; idx_start = idx_end; sg_start = sg_end; + size = 0; } out: diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 0fa53d3035eb..959c55e755ff 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -642,7 +642,8 @@ static int arm_lpae_map_sg(struct io_pgtable_ops *ops, unsigned long iova, arm_lpae_iopte prot; struct scatterlist *s; size_t mapped = 0; - int i, ret; + int i; + int ret = -EINVAL; unsigned int min_pagesz; struct io_pgtable_cfg *cfg = &data->iop.cfg; struct map_state ms; @@ -713,7 +714,7 @@ static int arm_lpae_map_sg(struct io_pgtable_ops *ops, unsigned long iova, out_err: /* Return the size of the partial mapping so that they can be undone */ *size = mapped; - return 0; + return ret; } static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl, diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h index 9ea96a64d380..00fd7388708a 100644 --- a/include/linux/io-pgtable.h +++ b/include/linux/io-pgtable.h @@ -193,8 +193,8 @@ struct io_pgtable_ops { * IOMMU drivers, and page table configuration. * * @map_sg: Map a scatterlist. Returns the number of bytes mapped, - * or 0 on failure. The size parameter contains the size - * of the partial mapping in case of failure. + * or -ve val on failure. The size parameter contains the + * size of the partial mapping in case of failure. * @is_iova_coherent: Checks coherency of given IOVA. Returns True if coherent * and False if non-coherent. * @iova_to_pte: Translate iova to Page Table Entry (PTE).