Skip to content

Introduce per-domain page sizes

Robin Murphy linux-arm-kernel linux-iommu linux-mediatek 1 version New

Get series with b4
b4 am [email protected]

Versions newest first

  1. v1 Latest0 of 5 patches 0 repliesNew

Patches in v1 No applies recorded yet

None of the 5 patches the cover letter announces are in this archive.

Reviews trailers per patch

No Reviewed-by, Acked-by or Tested-by trailers for v1 yet.

Read the v1 thread

Cover letter [PATCH 0/5] Introduce per-domain page sizes

Hi Joerg,

Quoted 28 lines · Joerg Roedel
Quoted 27 lines · Robin Murphy

Hi all,

Since this area seems to be in vogue at the moment, here's what I was working on when the related patches[1][2] popped up, which happens to be more or less the intersection of both. As I recycled some of Will's old series as a starting point, I've retained the cleanup patches from that with their original acks - hope that's OK.

Fortunately, this already looks rather like parts of Joerg's plan[3], so I hope it's a suitable first step. Below is a quick hacked-up example of the kind of caller-controlled special use-case alluded to, using the SMMU/HDLCD combo on Juno - for a 'real' implementation of this we'd want the group-based domain allocation call so the driver could throw the device at that and get its own non-default DMA ops domain to play with.

Robin.

[1]:http://thread.gmane.org/gmane.linux.kernel.iommu/12774 [2]:http://thread.gmane.org/gmane.linux.kernel.iommu/12901 [3]:http://article.gmane.org/gmane.linux.kernel.iommu/12937

Robin Murphy (4):
iommu: of: enforce const-ness of struct iommu_ops
iommu: Allow selecting page sizes per domain iommu/dma: Finish optimising higher-order allocations iommu/arm-smmu: Use per-domain page sizes.

Quoted 6 lines
Quoted 2 lines

Will Deacon (1):
iommu: remove unused priv field from struct iommu_ops

Okay, I am still no happy that this lifts the requirements of the iommu-api for the arm-smmu driver. But to get there we need more core changes and this code is a step in the right direction, so I applied it.

Thanks a lot! I was expecting to pick this up again after the merge window and post an updated version then; as you may already have found, patch 5 conflicts somewhat with the SMMUv2 context format changes in Will's updates branch. The correct resolution requires a bit of rewriting, so below is what that patch looks like when rebased on top of Will's branch. If you'd prefer it in actual merge resolution format, shout and I'll give that a go.

Thanks,
Robin.

--->8---
commit a940dae4e124523bc1cf282c8f36c79f960a0805

Author: Robin Murphy <[email protected]>
Date:   Mon Mar 14 14:25:07 2016 +0000

iommu/arm-smmu: Use per-domain page sizes.

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.

[rm: split from original patch, added SMMUv3]
drivers/iommu/arm-smmu-v3.c +1 -0
index 4ff73ff64e49..ebab33e77d67 100644
@@ -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) {

drivers/iommu/arm-smmu.c +1 -2
index 0bda956a025c..bf30490d6b18 100644
@@ -343,6 +343,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;
@@ -388,8 +389,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);
 
@@ -949,7 +948,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,
@@ -963,8 +962,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);
@@ -1793,19 +1792,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",