iommu/arm-smmu: Use per-domain page sizes.
authorRobin Murphy <robin.murphy@arm.com>
Mon, 9 May 2016 16:20:09 +0000 (17:20 +0100)
committerJoerg Roedel <jroedel@suse.de>
Mon, 9 May 2016 17:38:39 +0000 (19:38 +0200)
Now that we can accurately reflect the context format we choose for each
domain, do that instead of imposing the global lowest-common-denominator
restriction and potentially ending up with nothing. We currently have a
strict 1:1 correspondence between domains and context banks, so we don't
need to entertain the possibility of multiple formats _within_ a domain.

Signed-off-by: Will Deacon <will.deacon@arm.com>
[rm: split from original patch, added SMMUv3]
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/arm-smmu-v3.c
drivers/iommu/arm-smmu.c

index 4ff73ff64e4903079b5f540dcac0cd5c3a17eb26..ebab33e77d6729d5f3d2450d42761355f7cd29b8 100644 (file)
@@ -590,6 +590,7 @@ struct arm_smmu_device {
 
        unsigned long                   ias; /* IPA */
        unsigned long                   oas; /* PA */
+       unsigned long                   pgsize_bitmap;
 
 #define ARM_SMMU_MAX_ASIDS             (1 << 16)
        unsigned int                    asid_bits;
@@ -1516,8 +1517,6 @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
        return 0;
 }
 
-static struct iommu_ops arm_smmu_ops;
-
 static int arm_smmu_domain_finalise(struct iommu_domain *domain)
 {
        int ret;
@@ -1555,7 +1554,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
        }
 
        pgtbl_cfg = (struct io_pgtable_cfg) {
-               .pgsize_bitmap  = arm_smmu_ops.pgsize_bitmap,
+               .pgsize_bitmap  = smmu->pgsize_bitmap,
                .ias            = ias,
                .oas            = oas,
                .tlb            = &arm_smmu_gather_ops,
@@ -1566,7 +1565,7 @@ static int arm_smmu_domain_finalise(struct iommu_domain *domain)
        if (!pgtbl_ops)
                return -ENOMEM;
 
-       arm_smmu_ops.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
+       domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
        smmu_domain->pgtbl_ops = pgtbl_ops;
 
        ret = finalise_stage_fn(smmu_domain, &pgtbl_cfg);
@@ -2410,7 +2409,6 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
 {
        u32 reg;
        bool coherent;
-       unsigned long pgsize_bitmap = 0;
 
        /* IDR0 */
        reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0);
@@ -2541,13 +2539,16 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu)
 
        /* Page sizes */
        if (reg & IDR5_GRAN64K)
-               pgsize_bitmap |= SZ_64K | SZ_512M;
+               smmu->pgsize_bitmap |= SZ_64K | SZ_512M;
        if (reg & IDR5_GRAN16K)
-               pgsize_bitmap |= SZ_16K | SZ_32M;
+               smmu->pgsize_bitmap |= SZ_16K | SZ_32M;
        if (reg & IDR5_GRAN4K)
-               pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G;
+               smmu->pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G;
 
-       arm_smmu_ops.pgsize_bitmap &= pgsize_bitmap;
+       if (arm_smmu_ops.pgsize_bitmap == -1UL)
+               arm_smmu_ops.pgsize_bitmap = smmu->pgsize_bitmap;
+       else
+               arm_smmu_ops.pgsize_bitmap |= smmu->pgsize_bitmap;
 
        /* Output address size */
        switch (reg & IDR5_OAS_MASK << IDR5_OAS_SHIFT) {
index 7cd4ad98904a362da439ca4a3151724649d01316..0360919a5737afcdcca8d741b93f4cd087ac4a59 100644 (file)
@@ -351,6 +351,7 @@ struct arm_smmu_device {
        unsigned long                   va_size;
        unsigned long                   ipa_size;
        unsigned long                   pa_size;
+       unsigned long                   pgsize_bitmap;
 
        u32                             num_global_irqs;
        u32                             num_context_irqs;
@@ -396,8 +397,6 @@ struct arm_smmu_domain {
        struct iommu_domain             domain;
 };
 
-static struct iommu_ops arm_smmu_ops;
-
 static DEFINE_SPINLOCK(arm_smmu_devices_lock);
 static LIST_HEAD(arm_smmu_devices);
 
@@ -957,7 +956,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
        }
 
        pgtbl_cfg = (struct io_pgtable_cfg) {
-               .pgsize_bitmap  = arm_smmu_ops.pgsize_bitmap,
+               .pgsize_bitmap  = smmu->pgsize_bitmap,
                .ias            = ias,
                .oas            = oas,
                .tlb            = &arm_smmu_gather_ops,
@@ -971,8 +970,8 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
                goto out_clear_smmu;
        }
 
-       /* Update our support page sizes to reflect the page table format */
-       arm_smmu_ops.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
+       /* Update the domain's page sizes to reflect the page table format */
+       domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
 
        /* Initialise the context bank with our page table cfg */
        arm_smmu_init_context_bank(smmu_domain, &pgtbl_cfg);
@@ -1814,19 +1813,23 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
        }
 
        /* Now we've corralled the various formats, what'll it do? */
-       size = 0;
        if (smmu->features & ARM_SMMU_FEAT_FMT_AARCH32_S)
-               size |= SZ_4K | SZ_64K | SZ_1M | SZ_16M;
+               smmu->pgsize_bitmap |= SZ_4K | SZ_64K | SZ_1M | SZ_16M;
        if (smmu->features &
            (ARM_SMMU_FEAT_FMT_AARCH32_L | ARM_SMMU_FEAT_FMT_AARCH64_4K))
-               size |= SZ_4K | SZ_2M | SZ_1G;
+               smmu->pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G;
        if (smmu->features & ARM_SMMU_FEAT_FMT_AARCH64_16K)
-               size |= SZ_16K | SZ_32M;
+               smmu->pgsize_bitmap |= SZ_16K | SZ_32M;
        if (smmu->features & ARM_SMMU_FEAT_FMT_AARCH64_64K)
-               size |= SZ_64K | SZ_512M;
+               smmu->pgsize_bitmap |= SZ_64K | SZ_512M;
+
+       if (arm_smmu_ops.pgsize_bitmap == -1UL)
+               arm_smmu_ops.pgsize_bitmap = smmu->pgsize_bitmap;
+       else
+               arm_smmu_ops.pgsize_bitmap |= smmu->pgsize_bitmap;
+       dev_notice(smmu->dev, "\tSupported page sizes: 0x%08lx\n",
+                  smmu->pgsize_bitmap);
 
-       arm_smmu_ops.pgsize_bitmap &= size;
-       dev_notice(smmu->dev, "\tSupported page sizes: 0x%08lx\n", size);
 
        if (smmu->features & ARM_SMMU_FEAT_TRANS_S1)
                dev_notice(smmu->dev, "\tStage-1: %lu-bit VA -> %lu-bit IPA\n",