iommu/arm-smmu: add option to enable static context bank allocation

To implement slave side protection, programming of
global registers as well as secure context bank
registers is handed over to TZ. Now, instead of
dynamically allocating context banks, TZ allocates
CBs once in pre defined static manner during boot
and this allocation is maintained throughout the
life of system.

Add an option to enable use of this pre-defined
context bank allocation. We would be reading
through SMR and S2CR registers at run time
to identify CB allocated for a particular sid.

CRs-Fixed: 959535
Change-Id: I782470a2e4d2a66be17ed2b965ba52b7917592f6
Signed-off-by: Susheel Khiani <skhiani@codeaurora.org>
This commit is contained in:
Susheel Khiani 2015-11-17 13:15:20 +05:30 committed by David Keitel
parent c4db2e1dec
commit b3d402012c
2 changed files with 71 additions and 6 deletions

View file

@ -124,6 +124,15 @@ conditions.
a call back notifier on regulators in whcih SMMU can be halted
or resumed when regulator is powered down/up.
- qcom,enable-static-cb : Enables option to use pre-defined static context bank
allocation programmed by TZ. Global register including SMR and
S2CR registers are configured by TZ before kernel comes up and
this programming is not altered throughout the life of system.
We would be reading through these registers at run time to
identify CB allocated for a particular sid. SID masking isn't
supported as we are directly comparing client SID with ID bits
of SMR registers.
- clocks : List of clocks to be used during SMMU register access. See
Documentation/devicetree/bindings/clock/clock-bindings.txt
for information about the format. For each clock specified

View file

@ -363,6 +363,7 @@ struct arm_smmu_device {
#define ARM_SMMU_OPT_NO_SMR_CHECK (1 << 9)
#define ARM_SMMU_OPT_DYNAMIC (1 << 10)
#define ARM_SMMU_OPT_HALT (1 << 11)
#define ARM_SMMU_OPT_STATIC_CB (1 << 12)
u32 options;
enum arm_smmu_arch_version version;
@ -481,6 +482,7 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
{ ARM_SMMU_OPT_NO_SMR_CHECK, "qcom,no-smr-check" },
{ ARM_SMMU_OPT_DYNAMIC, "qcom,dynamic" },
{ ARM_SMMU_OPT_HALT, "qcom,enable-smmu-halt"},
{ ARM_SMMU_OPT_STATIC_CB, "qcom,enable-static-cb"},
{ 0, NULL},
};
@ -504,7 +506,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu);
static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
size_t size);
static bool arm_smmu_is_master_side_secure(struct arm_smmu_domain *smmu_domain);
static bool arm_smmu_is_static_cb(struct arm_smmu_device *smmu);
static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
{
@ -1453,6 +1455,11 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
writel_relaxed(reg, cb_base + ARM_SMMU_CB_SCTLR);
}
static bool arm_smmu_is_static_cb(struct arm_smmu_device *smmu)
{
return smmu->options & ARM_SMMU_OPT_STATIC_CB;
}
static bool arm_smmu_is_master_side_secure(struct arm_smmu_domain *smmu_domain)
{
return smmu_domain->secure_vmid != VMID_INVAL;
@ -1537,12 +1544,17 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
goto out;
}
ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
smmu->num_context_banks);
if (IS_ERR_VALUE(ret))
goto out;
if (cfg->cbndx == INVALID_CBNDX) {
ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
smmu->num_context_banks);
if (IS_ERR_VALUE(ret))
goto out;
cfg->cbndx = ret;
} else {
if (test_and_set_bit(cfg->cbndx, smmu->context_map))
goto out;
}
cfg->cbndx = ret;
if (smmu->version == ARM_SMMU_V1) {
cfg->irptndx = atomic_inc_return(&smmu->irptndx);
cfg->irptndx %= smmu->num_context_irqs;
@ -1917,6 +1929,40 @@ out:
return ret;
}
static int arm_smmu_populate_cb(struct arm_smmu_device *smmu,
struct arm_smmu_domain *smmu_domain, struct device *dev)
{
void __iomem *gr0_base;
struct arm_smmu_master_cfg *cfg;
struct arm_smmu_cfg *smmu_cfg = &smmu_domain->cfg;
int i;
u32 sid;
gr0_base = ARM_SMMU_GR0(smmu);
cfg = find_smmu_master_cfg(dev);
if (!cfg)
return -ENODEV;
sid = cfg->streamids[0];
for (i = 0; i < smmu->num_mapping_groups; i++) {
u32 smr, s2cr;
u8 cbndx;
smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(i));
if (sid == ((smr >> SMR_ID_SHIFT) & SMR_ID_MASK)) {
s2cr = readl_relaxed(gr0_base + ARM_SMMU_GR0_S2CR(i));
cbndx = (s2cr >> S2CR_CBNDX_SHIFT) & S2CR_CBNDX_MASK;
smmu_cfg->cbndx = cbndx;
return 0;
}
}
return -EINVAL;
}
static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
{
int ret;
@ -1975,6 +2021,16 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
}
smmu->attach_count++;
if (arm_smmu_is_static_cb(smmu)) {
ret = arm_smmu_populate_cb(smmu, smmu_domain, dev);
if (ret) {
dev_err(dev, "Failed to get valid context bank\n");
goto err_disable_clocks;
}
}
/* Ensure that the domain is finalised */
ret = arm_smmu_init_domain_context(domain, smmu);
if (IS_ERR_VALUE(ret))