diff options
| author | Neeti Desai <neetid@codeaurora.org> | 2015-03-09 19:36:03 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-22 11:11:58 -0700 |
| commit | e74807ec8aebd25c24f68c7e642c1e3eedc4975d (patch) | |
| tree | 9947b939da2c7b614a8e4e268f1166aa608b6be8 | |
| parent | 260963b57fbba2f6e45a7b7445c635434a56ad72 (diff) | |
iommu/arm-smmu: Add support for page table donation
For secure domains, the page tables need to be assigned
to the correct VMIDs. Add support for the same.
Change-Id: Ic46e61300463d969b35ebc5d4d20cfc30a4ba476
Signed-off-by: Neeti Desai <neetid@codeaurora.org>
| -rw-r--r-- | drivers/iommu/arm-smmu.c | 47 | ||||
| -rw-r--r-- | include/linux/iommu.h | 1 |
2 files changed, 46 insertions, 2 deletions
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index a810ae3b21b3..bcfa0e2b2eed 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -47,6 +47,7 @@ #include <linux/amba/bus.h> #include <soc/qcom/msm_tz_smmu.h> +#include <soc/qcom/secure_buffer.h> #include <asm/pgalloc.h> @@ -485,6 +486,7 @@ struct arm_smmu_domain { struct arm_smmu_cfg cfg; struct mutex lock; u32 attributes; + int secure_vmid; }; static DEFINE_SPINLOCK(arm_smmu_devices_lock); @@ -1244,6 +1246,18 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain) smmu_domain->smmu = NULL; } +static int arm_smmu_assign_call(phys_addr_t addr, u64 size, int dest_vmid) +{ + int dest_vmids[2] = {VMID_HLOS, dest_vmid}; + int dest_perms[2] = {PERM_READ | PERM_WRITE, PERM_READ}; + + if (dest_vmid == VMID_INVAL) + return 0; + + return hyp_assign_phys(addr, size, + dest_vmids, dest_perms, 2); +} + static int arm_smmu_domain_init(struct iommu_domain *domain) { struct arm_smmu_domain *smmu_domain; @@ -1262,6 +1276,7 @@ static int arm_smmu_domain_init(struct iommu_domain *domain) if (!pgd) goto out_free_domain; smmu_domain->cfg.pgd = pgd; + smmu_domain->secure_vmid = VMID_INVAL; mutex_init(&smmu_domain->lock); domain->priv = smmu_domain; @@ -1515,6 +1530,12 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) } else { arm_smmu_enable_clocks(smmu); } + ret = arm_smmu_assign_call(virt_to_phys(smmu_domain->cfg.pgd), + PAGE_SIZE, smmu_domain->secure_vmid); + if (ret) { + mutex_unlock(&smmu->attach_lock); + goto err_disable_clocks; + } mutex_unlock(&smmu->attach_lock); /* @@ -1628,6 +1649,7 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_domain *smmu_domain, { pte_t *pte, *start; pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF | ARM_SMMU_PTE_XN; + int ret; if (pmd_none(*pmd)) { /* Allocate a new set of tables */ @@ -1640,6 +1662,12 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_domain *smmu_domain, PAGE_SIZE); pmd_populate(NULL, pmd, table); arm_smmu_flush_pgtable(smmu_domain, pmd, sizeof(*pmd)); + ret = arm_smmu_assign_call(virt_to_phys(page_address(table)), + PAGE_SIZE, smmu_domain->secure_vmid); + if (ret) { + free_page((unsigned long)table); + return ret; + } } if (stage == 1) { @@ -1750,7 +1778,12 @@ static int arm_smmu_alloc_init_pmd(struct arm_smmu_domain *smmu_domain, arm_smmu_flush_pgtable(smmu_domain, pmd, PAGE_SIZE); pud_populate(NULL, pud, pmd); arm_smmu_flush_pgtable(smmu_domain, pud, sizeof(*pud)); - + ret = arm_smmu_assign_call(virt_to_phys(pmd), PAGE_SIZE, + smmu_domain->secure_vmid); + if (ret) { + free_page((unsigned long)pmd); + return ret; + } pmd += pmd_index(addr); } else #endif @@ -1785,7 +1818,12 @@ static int arm_smmu_alloc_init_pud(struct arm_smmu_domain *smmu_domain, arm_smmu_flush_pgtable(smmu_domain, pud, PAGE_SIZE); pgd_populate(NULL, pgd, pud); arm_smmu_flush_pgtable(smmu_domain, pgd, sizeof(*pgd)); - + ret = arm_smmu_assign_call(virt_to_phys(pud), PAGE_SIZE, + smmu_domain->secure_vmid); + if (ret) { + free_page((unsigned long)pud); + return ret; + } pud += pud_index(addr); } else #endif @@ -2205,6 +2243,11 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain, ~(1 << DOMAIN_ATTR_COHERENT_HTW_DISABLE); return 0; } + case DOMAIN_ATTR_SECURE_VMID: + { + smmu_domain->secure_vmid = *((int *)data); + return 0; + } default: return -ENODEV; } diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 85ec8fda186c..cf12d3a77af4 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -87,6 +87,7 @@ enum iommu_attr { DOMAIN_ATTR_NESTING, /* two stages of translation */ DOMAIN_ATTR_COHERENT_HTW_DISABLE, DOMAIN_ATTR_PT_BASE_ADDR, + DOMAIN_ATTR_SECURE_VMID, DOMAIN_ATTR_MAX, }; |
