summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeeti Desai <neetid@codeaurora.org>2015-03-09 19:36:03 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:11:58 -0700
commite74807ec8aebd25c24f68c7e642c1e3eedc4975d (patch)
tree9947b939da2c7b614a8e4e268f1166aa608b6be8
parent260963b57fbba2f6e45a7b7445c635434a56ad72 (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.c47
-rw-r--r--include/linux/iommu.h1
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,
};