summaryrefslogtreecommitdiffstats
path: root/drivers/iommu/arm-smmu-v3.c
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2015-07-16 17:50:12 +0100
committerWill Deacon <will.deacon@arm.com>2015-07-31 11:38:25 +0100
commit28c8b4045b18b013e05656b493ce9a57cbf1f09a (patch)
treefcaa96123a1917e6488ed182e255fdd64df6a04d /drivers/iommu/arm-smmu-v3.c
parentec11d63c677bbba15e65a35f5ba06c1d6eba4dbe (diff)
downloadlinux-28c8b4045b18b013e05656b493ce9a57cbf1f09a.tar.gz
linux-28c8b4045b18b013e05656b493ce9a57cbf1f09a.tar.bz2
linux-28c8b4045b18b013e05656b493ce9a57cbf1f09a.zip
iommu/arm-smmu: Limit 2-level strtab allocation for small SID sizes
If the StreamIDs in a system can all be resolved by a single level-2 stream table (i.e. SIDSIZE < SPLIT), then we currently get our maths wrong and allocate the largest strtab we support, thanks to unsigned overflow in our calculation. This patch fixes the issue by checking the SIDSIZE explicitly when calculating the size of our first-level stream table. Reported-by: Matt Evans <matt.evans@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/iommu/arm-smmu-v3.c')
-rw-r--r--drivers/iommu/arm-smmu-v3.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index c2c1ad8915d9..4f093373f4c3 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -2054,9 +2054,17 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu)
int ret;
struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
- /* Calculate the L1 size, capped to the SIDSIZE */
- size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3);
- size = min(size, smmu->sid_bits - STRTAB_SPLIT);
+ /*
+ * If we can resolve everything with a single L2 table, then we
+ * just need a single L1 descriptor. Otherwise, calculate the L1
+ * size, capped to the SIDSIZE.
+ */
+ if (smmu->sid_bits < STRTAB_SPLIT) {
+ size = 0;
+ } else {
+ size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3);
+ size = min(size, smmu->sid_bits - STRTAB_SPLIT);
+ }
cfg->num_l1_ents = 1 << size;
size += STRTAB_SPLIT;