summaryrefslogtreecommitdiff
path: root/drivers/iommu/arm-smmu.c
diff options
context:
space:
mode:
authorLiam Mark <lmark@codeaurora.org>2016-10-14 10:37:23 -0700
committerLiam Mark <lmark@codeaurora.org>2016-11-11 09:46:54 -0800
commitb40f602bfa240777ab4ffaa1218031dac4e81aa7 (patch)
tree6f32be70ab6f1c35f01dc078065eaffab45f43b9 /drivers/iommu/arm-smmu.c
parent8e6988760075ac91403ba2c5096e848197d55704 (diff)
iommu/arm-smmu: support mapping before enabling S1 translations
For performance reasons there are clients who would like to move from stage 1 bypass to stage 1 enabled without having to stop their device. Currently clients need to stop their device because they have to create the required stage 1 mappings before re-enabling the device. Add the new DOMAIN_ATTR_EARLY_MAP domain attribute to allow clients to create stage 1 mappings after attaching but before enabling stage 1 translations. If the clients set the DOMAIN_ATTR_EARLY_MAP domain attribute to 1 before attaching then then once they attach the SMMU driver won't enable stage 1 translations. This gives the client the opportunity to create the required early mappings (for example using iommu_map). When the client has finished creating the necessary early mappings the client can then set the DOMAIN_ATTR_EARLY_MAP domain attribute to 0, this will in turn enable stage 1 translations. Change-Id: I9e95c5d2130f1d371e201eac69dec140cc773b1f Signed-off-by: Liam Mark <lmark@codeaurora.org>
Diffstat (limited to 'drivers/iommu/arm-smmu.c')
-rw-r--r--drivers/iommu/arm-smmu.c50
1 files changed, 49 insertions, 1 deletions
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index fda10abae58a..4ed3fd177f15 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -528,6 +528,8 @@ static bool arm_smmu_is_static_cb(struct arm_smmu_device *smmu);
static bool arm_smmu_is_slave_side_secure(struct arm_smmu_domain *smmu_domain);
static bool arm_smmu_has_secure_vmid(struct arm_smmu_domain *smmu_domain);
+static int arm_smmu_enable_s1_translations(struct arm_smmu_domain *smmu_domain);
+
static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
{
return container_of(dom, struct arm_smmu_domain, domain);
@@ -1604,7 +1606,8 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
/* SCTLR */
reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_EAE_SBOP;
- if (!(smmu_domain->attributes & (1 << DOMAIN_ATTR_S1_BYPASS)) ||
+ if ((!(smmu_domain->attributes & (1 << DOMAIN_ATTR_S1_BYPASS)) &&
+ !(smmu_domain->attributes & (1 << DOMAIN_ATTR_EARLY_MAP))) ||
!stage1)
reg |= SCTLR_M;
if (stage1)
@@ -3043,6 +3046,11 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
ret = 0;
break;
}
+ case DOMAIN_ATTR_EARLY_MAP:
+ *((int *)data) = !!(smmu_domain->attributes
+ & (1 << DOMAIN_ATTR_EARLY_MAP));
+ ret = 0;
+ break;
default:
ret = -ENODEV;
break;
@@ -3148,6 +3156,24 @@ static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
smmu_domain->attributes |= 1 << DOMAIN_ATTR_FAST;
ret = 0;
break;
+ case DOMAIN_ATTR_EARLY_MAP: {
+ int early_map = *((int *)data);
+
+ ret = 0;
+ if (early_map) {
+ smmu_domain->attributes |=
+ 1 << DOMAIN_ATTR_EARLY_MAP;
+ } else {
+ if (smmu_domain->smmu)
+ ret = arm_smmu_enable_s1_translations(
+ smmu_domain);
+
+ if (!ret)
+ smmu_domain->attributes &=
+ ~(1 << DOMAIN_ATTR_EARLY_MAP);
+ }
+ break;
+ }
default:
ret = -ENODEV;
break;
@@ -3158,6 +3184,28 @@ out_unlock:
return ret;
}
+
+static int arm_smmu_enable_s1_translations(struct arm_smmu_domain *smmu_domain)
+{
+ struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
+ struct arm_smmu_device *smmu = smmu_domain->smmu;
+ void __iomem *cb_base;
+ u32 reg;
+ int ret;
+
+ cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+ ret = arm_smmu_enable_clocks(smmu);
+ if (ret)
+ return ret;
+
+ reg = readl_relaxed(cb_base + ARM_SMMU_CB_SCTLR);
+ reg |= SCTLR_M;
+
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_SCTLR);
+ arm_smmu_disable_clocks(smmu);
+ return ret;
+}
+
static int arm_smmu_dma_supported(struct iommu_domain *domain,
struct device *dev, u64 mask)
{