iommu/arm-smmu: Do not access non-existing S2CR registers

The number of S2CR registers is not properly set when stream
matching is not supported. Fix this and add check that we do not try to
access outside of the number of S2CR regisrers.

Signed-off-by: Olav Haugan <ohaugan@codeaurora.org>
[will: added missing NUMSIDB_* definitions]
Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
Olav Haugan 2014-08-22 17:12:32 -07:00 committed by Will Deacon
parent 43b412bedb
commit 3c8766d0ca

View File

@ -146,6 +146,8 @@
#define ID0_CTTW (1 << 14) #define ID0_CTTW (1 << 14)
#define ID0_NUMIRPT_SHIFT 16 #define ID0_NUMIRPT_SHIFT 16
#define ID0_NUMIRPT_MASK 0xff #define ID0_NUMIRPT_MASK 0xff
#define ID0_NUMSIDB_SHIFT 9
#define ID0_NUMSIDB_MASK 0xf
#define ID0_NUMSMRG_SHIFT 0 #define ID0_NUMSMRG_SHIFT 0
#define ID0_NUMSMRG_MASK 0xff #define ID0_NUMSMRG_MASK 0xff
@ -524,9 +526,18 @@ static int register_smmu_master(struct arm_smmu_device *smmu,
master->of_node = masterspec->np; master->of_node = masterspec->np;
master->cfg.num_streamids = masterspec->args_count; master->cfg.num_streamids = masterspec->args_count;
for (i = 0; i < master->cfg.num_streamids; ++i) for (i = 0; i < master->cfg.num_streamids; ++i) {
master->cfg.streamids[i] = masterspec->args[i]; u16 streamid = masterspec->args[i];
if (!(smmu->features & ARM_SMMU_FEAT_STREAM_MATCH) &&
(streamid >= smmu->num_mapping_groups)) {
dev_err(dev,
"stream ID for master device %s greater than maximum allowed (%d)\n",
masterspec->np->name, smmu->num_mapping_groups);
return -ERANGE;
}
master->cfg.streamids[i] = streamid;
}
return insert_smmu_master(smmu, master); return insert_smmu_master(smmu, master);
} }
@ -1624,7 +1635,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
/* Mark all SMRn as invalid and all S2CRn as bypass */ /* Mark all SMRn as invalid and all S2CRn as bypass */
for (i = 0; i < smmu->num_mapping_groups; ++i) { for (i = 0; i < smmu->num_mapping_groups; ++i) {
writel_relaxed(~SMR_VALID, gr0_base + ARM_SMMU_GR0_SMR(i)); writel_relaxed(0, gr0_base + ARM_SMMU_GR0_SMR(i));
writel_relaxed(S2CR_TYPE_BYPASS, writel_relaxed(S2CR_TYPE_BYPASS,
gr0_base + ARM_SMMU_GR0_S2CR(i)); gr0_base + ARM_SMMU_GR0_S2CR(i));
} }
@ -1759,6 +1770,9 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
dev_notice(smmu->dev, dev_notice(smmu->dev,
"\tstream matching with %u register groups, mask 0x%x", "\tstream matching with %u register groups, mask 0x%x",
smmu->num_mapping_groups, mask); smmu->num_mapping_groups, mask);
} else {
smmu->num_mapping_groups = (id >> ID0_NUMSIDB_SHIFT) &
ID0_NUMSIDB_MASK;
} }
/* ID1 */ /* ID1 */
@ -1887,6 +1901,10 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
smmu->irqs[i] = irq; smmu->irqs[i] = irq;
} }
err = arm_smmu_device_cfg_probe(smmu);
if (err)
return err;
i = 0; i = 0;
smmu->masters = RB_ROOT; smmu->masters = RB_ROOT;
while (!of_parse_phandle_with_args(dev->of_node, "mmu-masters", while (!of_parse_phandle_with_args(dev->of_node, "mmu-masters",
@ -1903,10 +1921,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev)
} }
dev_notice(dev, "registered %d master devices\n", i); dev_notice(dev, "registered %d master devices\n", i);
err = arm_smmu_device_cfg_probe(smmu);
if (err)
goto out_put_masters;
parse_driver_options(smmu); parse_driver_options(smmu);
if (smmu->version > 1 && if (smmu->version > 1 &&