iommu/arm-smmu: Make atomic scm call in slave side protection mode

When we have SMMU halt/resume functionality
enabled we try to program MICRO_MMU_CTRL register
which is part of SMMU implementation defined
register space. Now targets which have slave side
protection mechanism, implementation defined
register space of SMMU is protected by XPUs along
with other SMMU global register space. As a result
we would get a fault if we directly try to program
MICRO_MMU_CTRL register.

Instead we request TZ through atomic scm call to
program this register for us. Since we have read only
permission available for these registers we need to
ensure that write operation is requested through TZ.

CRs-Fixed: 959535
Change-Id: Ie257553a25bb11785b69568d8eccbef91d8d18e0
Signed-off-by: Susheel Khiani <skhiani@codeaurora.org>
This commit is contained in:
Susheel Khiani 2016-02-04 17:08:19 +05:30 committed by David Keitel
parent 84072b90d2
commit a6fba6085d

View file

@ -342,6 +342,7 @@ struct arm_smmu_device {
void __iomem *base;
unsigned long size;
phys_addr_t phys_addr;
unsigned long pgshift;
#define ARM_SMMU_FEAT_COHERENT_WALK (1 << 0)
@ -2491,7 +2492,20 @@ static int __arm_smmu_halt(struct arm_smmu_device *smmu, bool wait)
reg = readl_relaxed(impl_def1_base + IMPL_DEF1_MICRO_MMU_CTRL);
reg |= MICRO_MMU_CTRL_LOCAL_HALT_REQ;
writel_relaxed(reg, impl_def1_base + IMPL_DEF1_MICRO_MMU_CTRL);
if (arm_smmu_is_static_cb(smmu)) {
phys_addr_t impl_def1_base_phys = impl_def1_base - smmu->base +
smmu->phys_addr;
if (scm_io_write(impl_def1_base_phys +
IMPL_DEF1_MICRO_MMU_CTRL, reg)) {
dev_err(smmu->dev,
"scm_io_write fail. SMMU might not be halted");
return -EINVAL;
}
} else {
writel_relaxed(reg, impl_def1_base + IMPL_DEF1_MICRO_MMU_CTRL);
}
return wait ? arm_smmu_wait_for_halt(smmu) : 0;
}
@ -2523,7 +2537,18 @@ static void arm_smmu_resume(struct arm_smmu_device *smmu)
reg = readl_relaxed(impl_def1_base + IMPL_DEF1_MICRO_MMU_CTRL);
reg &= ~MICRO_MMU_CTRL_LOCAL_HALT_REQ;
writel_relaxed(reg, impl_def1_base + IMPL_DEF1_MICRO_MMU_CTRL);
if (arm_smmu_is_static_cb(smmu)) {
phys_addr_t impl_def1_base_phys = impl_def1_base - smmu->base +
smmu->phys_addr;
if (scm_io_write(impl_def1_base_phys +
IMPL_DEF1_MICRO_MMU_CTRL, reg))
dev_err(smmu->dev,
"scm_io_write fail. SMMU might not be resumed");
} else {
writel_relaxed(reg, impl_def1_base + IMPL_DEF1_MICRO_MMU_CTRL);
}
}
static phys_addr_t __arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
@ -3496,6 +3521,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
smmu->version = (enum arm_smmu_arch_version)of_id->data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
smmu->phys_addr = res->start;
smmu->base = devm_ioremap_resource(dev, res);
if (IS_ERR(smmu->base))
return PTR_ERR(smmu->base);