diff options
author | Liam Mark <lmark@codeaurora.org> | 2016-10-14 10:37:23 -0700 |
---|---|---|
committer | Liam Mark <lmark@codeaurora.org> | 2016-11-11 09:46:54 -0800 |
commit | b40f602bfa240777ab4ffaa1218031dac4e81aa7 (patch) | |
tree | 6f32be70ab6f1c35f01dc078065eaffab45f43b9 /drivers/iommu/arm-smmu.c | |
parent | 8e6988760075ac91403ba2c5096e848197d55704 (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.c | 50 |
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) { |