diff options
author | Robin Murphy <robin.murphy@arm.com> | 2016-09-12 12:13:48 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2016-09-16 04:34:18 -0400 |
commit | 21174240e4f4439bb8ed6c116cdbdc03eba2126e (patch) | |
tree | 2498b0d9666a2d8abec99731efc42cc42039bd31 /drivers/iommu/arm-smmu.c | |
parent | 95fa99aa402ad516ec825057a168f395ece39a2e (diff) |
iommu/arm-smmu: Handle stream IDs more dynamically
Rather than assuming fixed worst-case values for stream IDs and SMR
masks, keep track of whatever implemented bits the hardware actually
reports. This also obviates the slightly questionable validation of SMR
fields in isolation - rather than aborting the whole SMMU probe for a
hardware configuration which is still architecturally valid, we can
simply refuse masters later if they try to claim an unrepresentable ID
or mask (which almost certainly implies a DT error anyway).
Acked-by: Will Deacon <will.deacon@arm.com>
Tested-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'drivers/iommu/arm-smmu.c')
-rw-r--r-- | drivers/iommu/arm-smmu.c | 43 |
1 files changed, 22 insertions, 21 deletions
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 4b1c87e947fd..f86d7887f69a 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c | |||
@@ -165,9 +165,7 @@ | |||
165 | #define ARM_SMMU_GR0_SMR(n) (0x800 + ((n) << 2)) | 165 | #define ARM_SMMU_GR0_SMR(n) (0x800 + ((n) << 2)) |
166 | #define SMR_VALID (1 << 31) | 166 | #define SMR_VALID (1 << 31) |
167 | #define SMR_MASK_SHIFT 16 | 167 | #define SMR_MASK_SHIFT 16 |
168 | #define SMR_MASK_MASK 0x7fff | ||
169 | #define SMR_ID_SHIFT 0 | 168 | #define SMR_ID_SHIFT 0 |
170 | #define SMR_ID_MASK 0x7fff | ||
171 | 169 | ||
172 | #define ARM_SMMU_GR0_S2CR(n) (0xc00 + ((n) << 2)) | 170 | #define ARM_SMMU_GR0_S2CR(n) (0xc00 + ((n) << 2)) |
173 | #define S2CR_CBNDX_SHIFT 0 | 171 | #define S2CR_CBNDX_SHIFT 0 |
@@ -346,6 +344,8 @@ struct arm_smmu_device { | |||
346 | atomic_t irptndx; | 344 | atomic_t irptndx; |
347 | 345 | ||
348 | u32 num_mapping_groups; | 346 | u32 num_mapping_groups; |
347 | u16 streamid_mask; | ||
348 | u16 smr_mask_mask; | ||
349 | DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS); | 349 | DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS); |
350 | 350 | ||
351 | unsigned long va_size; | 351 | unsigned long va_size; |
@@ -1715,39 +1715,40 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) | |||
1715 | dev_notice(smmu->dev, | 1715 | dev_notice(smmu->dev, |
1716 | "\t(IDR0.CTTW overridden by dma-coherent property)\n"); | 1716 | "\t(IDR0.CTTW overridden by dma-coherent property)\n"); |
1717 | 1717 | ||
1718 | /* Max. number of entries we have for stream matching/indexing */ | ||
1719 | size = 1 << ((id >> ID0_NUMSIDB_SHIFT) & ID0_NUMSIDB_MASK); | ||
1720 | smmu->streamid_mask = size - 1; | ||
1718 | if (id & ID0_SMS) { | 1721 | if (id & ID0_SMS) { |
1719 | u32 smr, sid, mask; | 1722 | u32 smr; |
1720 | 1723 | ||
1721 | smmu->features |= ARM_SMMU_FEAT_STREAM_MATCH; | 1724 | smmu->features |= ARM_SMMU_FEAT_STREAM_MATCH; |
1722 | smmu->num_mapping_groups = (id >> ID0_NUMSMRG_SHIFT) & | 1725 | size = (id >> ID0_NUMSMRG_SHIFT) & ID0_NUMSMRG_MASK; |
1723 | ID0_NUMSMRG_MASK; | 1726 | if (size == 0) { |
1724 | if (smmu->num_mapping_groups == 0) { | ||
1725 | dev_err(smmu->dev, | 1727 | dev_err(smmu->dev, |
1726 | "stream-matching supported, but no SMRs present!\n"); | 1728 | "stream-matching supported, but no SMRs present!\n"); |
1727 | return -ENODEV; | 1729 | return -ENODEV; |
1728 | } | 1730 | } |
1729 | 1731 | ||
1730 | smr = SMR_MASK_MASK << SMR_MASK_SHIFT; | 1732 | /* |
1731 | smr |= (SMR_ID_MASK << SMR_ID_SHIFT); | 1733 | * SMR.ID bits may not be preserved if the corresponding MASK |
1734 | * bits are set, so check each one separately. We can reject | ||
1735 | * masters later if they try to claim IDs outside these masks. | ||
1736 | */ | ||
1737 | smr = smmu->streamid_mask << SMR_ID_SHIFT; | ||
1732 | writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0)); | 1738 | writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0)); |
1733 | smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0)); | 1739 | smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0)); |
1740 | smmu->streamid_mask = smr >> SMR_ID_SHIFT; | ||
1734 | 1741 | ||
1735 | mask = (smr >> SMR_MASK_SHIFT) & SMR_MASK_MASK; | 1742 | smr = smmu->streamid_mask << SMR_MASK_SHIFT; |
1736 | sid = (smr >> SMR_ID_SHIFT) & SMR_ID_MASK; | 1743 | writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0)); |
1737 | if ((mask & sid) != sid) { | 1744 | smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0)); |
1738 | dev_err(smmu->dev, | 1745 | smmu->smr_mask_mask = smr >> SMR_MASK_SHIFT; |
1739 | "SMR mask bits (0x%x) insufficient for ID field (0x%x)\n", | ||
1740 | mask, sid); | ||
1741 | return -ENODEV; | ||
1742 | } | ||
1743 | 1746 | ||
1744 | dev_notice(smmu->dev, | 1747 | dev_notice(smmu->dev, |
1745 | "\tstream matching with %u register groups, mask 0x%x", | 1748 | "\tstream matching with %lu register groups, mask 0x%x", |
1746 | smmu->num_mapping_groups, mask); | 1749 | size, smmu->smr_mask_mask); |
1747 | } else { | ||
1748 | smmu->num_mapping_groups = (id >> ID0_NUMSIDB_SHIFT) & | ||
1749 | ID0_NUMSIDB_MASK; | ||
1750 | } | 1750 | } |
1751 | smmu->num_mapping_groups = size; | ||
1751 | 1752 | ||
1752 | if (smmu->version < ARM_SMMU_V2 || !(id & ID0_PTFS_NO_AARCH32)) { | 1753 | if (smmu->version < ARM_SMMU_V2 || !(id & ID0_PTFS_NO_AARCH32)) { |
1753 | smmu->features |= ARM_SMMU_FEAT_FMT_AARCH32_L; | 1754 | smmu->features |= ARM_SMMU_FEAT_FMT_AARCH32_L; |