diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 58d7f98b8055..59559fbc2cfe 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -414,6 +414,16 @@ static bool arm_smmu_is_static_cb(struct arm_smmu_device *smmu); static bool arm_smmu_is_master_side_secure(struct arm_smmu_domain *smmu_domain); static bool arm_smmu_is_slave_side_secure(struct arm_smmu_domain *smmu_domain); +static int msm_secure_smmu_map(struct iommu_domain *domain, unsigned long iova, + phys_addr_t paddr, size_t size, int prot); +static size_t msm_secure_smmu_unmap(struct iommu_domain *domain, + unsigned long iova, + size_t size); +static size_t msm_secure_smmu_map_sg(struct iommu_domain *domain, + unsigned long iova, + struct scatterlist *sg, + unsigned int nents, int prot); + static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom) { return container_of(dom, struct arm_smmu_domain, domain); @@ -2493,6 +2503,9 @@ static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova, if (!ops) return -ENODEV; + if (arm_smmu_is_slave_side_secure(smmu_domain)) + return msm_secure_smmu_map(domain, iova, paddr, size, prot); + arm_smmu_secure_domain_lock(smmu_domain); spin_lock_irqsave(&smmu_domain->cb_lock, flags); @@ -2532,6 +2545,9 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, if (!ops) return 0; + if (arm_smmu_is_slave_side_secure(smmu_domain)) + return msm_secure_smmu_unmap(domain, iova, size); + ret = arm_smmu_domain_power_on(domain, smmu_domain->smmu); if (ret) return ret; @@ -2569,6 +2585,9 @@ static size_t arm_smmu_map_sg(struct iommu_domain *domain, unsigned long iova, if (!ops) return -ENODEV; + if (arm_smmu_is_slave_side_secure(smmu_domain)) + return msm_secure_smmu_map_sg(domain, iova, sg, nents, prot); + ret = arm_smmu_domain_power_on(domain, smmu_domain->smmu); if (ret) return ret; @@ -2744,6 +2763,58 @@ struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode) return dev ? dev_get_drvdata(dev) : NULL; } +#ifdef CONFIG_MSM_TZ_SMMU +static int msm_secure_smmu_map(struct iommu_domain *domain, unsigned long iova, + phys_addr_t paddr, size_t size, int prot) +{ + size_t ret; + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops; + + ret = ops->map(ops, iova, paddr, size, prot); + + return ret; +} + +static size_t msm_secure_smmu_unmap(struct iommu_domain *domain, + unsigned long iova, + size_t size) +{ + size_t ret; + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops; + + ret = arm_smmu_domain_power_on(domain, smmu_domain->smmu); + if (ret) + return ret; + + ret = ops->unmap(ops, iova, size); + + arm_smmu_domain_power_off(domain, smmu_domain->smmu); + + return ret; +} + +static size_t msm_secure_smmu_map_sg(struct iommu_domain *domain, + unsigned long iova, + struct scatterlist *sg, + unsigned int nents, int prot) +{ + int ret; + size_t size; + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + struct io_pgtable_ops *ops = smmu_domain->pgtbl_ops; + + ret = ops->map_sg(ops, iova, sg, nents, prot, &size); + + if (!ret) + msm_secure_smmu_unmap(domain, iova, size); + + return ret; +} + +#endif + static int arm_smmu_add_device(struct device *dev) { struct arm_smmu_device *smmu; diff --git a/drivers/iommu/io-pgtable-msm-secure.c b/drivers/iommu/io-pgtable-msm-secure.c index 65f6b7ffe6dc..f2d29a34af3b 100644 --- a/drivers/iommu/io-pgtable-msm-secure.c +++ b/drivers/iommu/io-pgtable-msm-secure.c @@ -41,6 +41,8 @@ struct msm_secure_io_pgtable { struct io_pgtable iop; + /* lock required while operating on page tables */ + struct mutex pgtbl_lock; }; int msm_iommu_sec_pgtbl_init(void) @@ -133,6 +135,7 @@ static int msm_secure_map(struct io_pgtable_ops *ops, unsigned long iova, flush_va_end = (void *) (((unsigned long) flush_va) + sizeof(phys_addr_t)); + mutex_lock(&data->pgtbl_lock); /* * Ensure that the buffer is in RAM by the time it gets to TZ */ @@ -142,10 +145,11 @@ static int msm_secure_map(struct io_pgtable_ops *ops, unsigned long iova, SCM_VAL, SCM_VAL, SCM_VAL); if (is_scm_armv8()) { - ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_MP, + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, IOMMU_SECURE_MAP2_FLAT), &desc); resp = desc.ret[0]; } + mutex_unlock(&data->pgtbl_lock); if (ret || resp) return -EINVAL; @@ -258,11 +262,13 @@ static int msm_secure_map_sg(struct io_pgtable_ops *ops, unsigned long iova, flush_va_end = (void *) (((unsigned long) flush_va) + (cnt * sizeof(*pa_list))); + + mutex_lock(&data->pgtbl_lock); dmac_clean_range(flush_va, flush_va_end); if (is_scm_armv8()) { - ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_MP, - IOMMU_SECURE_MAP2_FLAT), &desc); + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, + IOMMU_SECURE_MAP2_FLAT), &desc); resp = desc.ret[0]; if (ret || resp) @@ -270,6 +276,7 @@ static int msm_secure_map_sg(struct io_pgtable_ops *ops, unsigned long iova, else ret = len; } + mutex_unlock(&data->pgtbl_lock); kfree(pa_list); return ret; @@ -293,13 +300,15 @@ static size_t msm_secure_unmap(struct io_pgtable_ops *ops, unsigned long iova, desc.args[4] = IOMMU_TLBINVAL_FLAG; desc.arginfo = SCM_ARGS(5); + mutex_lock(&data->pgtbl_lock); if (is_scm_armv8()) { - ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_MP, - IOMMU_SECURE_UNMAP2_FLAT), &desc); + ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, + IOMMU_SECURE_UNMAP2_FLAT), &desc); if (!ret) ret = len; } + mutex_unlock(&data->pgtbl_lock); return ret; } @@ -324,6 +333,7 @@ msm_secure_alloc_pgtable_data(struct io_pgtable_cfg *cfg) .unmap = msm_secure_unmap, .iova_to_phys = msm_secure_iova_to_phys, }; + mutex_init(&data->pgtbl_lock); return data; } diff --git a/include/soc/qcom/msm_tz_smmu.h b/include/soc/qcom/msm_tz_smmu.h index 1863c231852d..54946b9f436a 100644 --- a/include/soc/qcom/msm_tz_smmu.h +++ b/include/soc/qcom/msm_tz_smmu.h @@ -88,6 +88,29 @@ static inline int register_iommu_sec_ptbl(void) { return -EINVAL; } + +static inline size_t msm_secure_smmu_unmap(struct iommu_domain *domain, + unsigned long iova, + size_t size) +{ + return -EINVAL; +} + +static inline size_t msm_secure_smmu_map_sg(struct iommu_domain *domain, + unsigned long iova, + struct scatterlist *sg, + unsigned int nents, int prot) +{ + return -EINVAL; +} + +static inline int msm_secure_smmu_map(struct iommu_domain *domain, + unsigned long iova, + phys_addr_t paddr, size_t size, int prot) +{ + return -EINVAL; +} + #endif /* CONFIG_MSM_TZ_SMMU */ #endif /* __MSM_TZ_SMMU_H__ */