On Wed, Jul 10, 2019 at 05:45:37PM +0100, Robin Murphy wrote: > Hi Jordan, > > On 08/07/2019 20:00, Jordan Crouse wrote: > >Add a new sub-format ARM_64_LPAE_SPLIT_S1 to create and set up split > >pagetables (TTBR0 and TTBR1). The initialization function sets up the > >correct va_size and sign extension bits and programs the TCR registers. > >Split pagetable formats use their own own map/unmap wrappers to ensure > >that the correct pagetable is selected based on the incoming iova but > >most of the heavy lifting is common to the other formats. > > I'm somewhat concerned that this implementation is very closely tied to the > current Adreno use-case, and won't easily generalise in future to other > potential TTBR1 uses which have been tossed around, like > SMMUv3-without-substream-ID.
I haven't heard about these use-cases. I figured v3 would be all PASID all the time. If you have details, I can see if I can avoid painting v3 into a corner. > Furthermore, even for the Adreno pretend-PASID case it appears to be a bit > too fragile for comfort - given that a DOMAIN_ATTR_SPLIT_TABLES domain > doesn't look any different from a regular one from the users' point of view, > what's to stop them making "without PASID" mappings in the lower half of the > address space, and thus unwittingly pulling the rug out from under their own > feet upon attaching an aux domain? In fact allocating a TTBR0 table at all > for the main domain seems like little more than a waste of memory. That makes sense. Would it work better if we made a type ARM_64_LPAE_TTBR1_S1 that only allocated memory for TTBR1 and set TBR.EDP0 to trigger faults for TTBR0? Then we could get rid of most of the extra stuff in io-pgtable-arm.c and I think that would meet most of your concerns. Jordan > > > >Signed-off-by: Jordan Crouse <jcro...@codeaurora.org> > >--- > > > > drivers/iommu/io-pgtable-arm.c | 261 > > +++++++++++++++++++++++++++++++++++++---- > > drivers/iommu/io-pgtable.c | 1 + > > include/linux/io-pgtable.h | 2 + > > 3 files changed, 240 insertions(+), 24 deletions(-) > > > >diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c > >index 161a7d56..aec35e5 100644 > >--- a/drivers/iommu/io-pgtable-arm.c > >+++ b/drivers/iommu/io-pgtable-arm.c > >@@ -118,7 +118,12 @@ > > #define ARM_LPAE_TCR_TG0_64K (1 << 14) > > #define ARM_LPAE_TCR_TG0_16K (2 << 14) > >+#define ARM_LPAE_TCR_TG1_4K (0 << 30) > >+#define ARM_LPAE_TCR_TG1_64K (1 << 30) > >+#define ARM_LPAE_TCR_TG1_16K (2 << 30) > >+ > > #define ARM_LPAE_TCR_SH0_SHIFT 12 > >+#define ARM_LPAE_TCR_SH1_SHIFT 28 > > #define ARM_LPAE_TCR_SH0_MASK 0x3 > > #define ARM_LPAE_TCR_SH_NS 0 > > #define ARM_LPAE_TCR_SH_OS 2 > >@@ -126,6 +131,8 @@ > > #define ARM_LPAE_TCR_ORGN0_SHIFT 10 > > #define ARM_LPAE_TCR_IRGN0_SHIFT 8 > >+#define ARM_LPAE_TCR_ORGN1_SHIFT 26 > >+#define ARM_LPAE_TCR_IRGN1_SHIFT 24 > > #define ARM_LPAE_TCR_RGN_MASK 0x3 > > #define ARM_LPAE_TCR_RGN_NC 0 > > #define ARM_LPAE_TCR_RGN_WBWA 1 > >@@ -136,6 +143,7 @@ > > #define ARM_LPAE_TCR_SL0_MASK 0x3 > > #define ARM_LPAE_TCR_T0SZ_SHIFT 0 > >+#define ARM_LPAE_TCR_T1SZ_SHIFT 16 > > #define ARM_LPAE_TCR_SZ_MASK 0xf > > #define ARM_LPAE_TCR_PS_SHIFT 16 > >@@ -152,6 +160,14 @@ > > #define ARM_LPAE_TCR_PS_48_BIT 0x5ULL > > #define ARM_LPAE_TCR_PS_52_BIT 0x6ULL > >+#define ARM_LPAE_TCR_SEP_SHIFT 47 > >+#define ARM_LPAE_TCR_SEP_31 (0x0ULL << ARM_LPAE_TCR_SEP_SHIFT) > >+#define ARM_LPAE_TCR_SEP_35 (0x1ULL << ARM_LPAE_TCR_SEP_SHIFT) > >+#define ARM_LPAE_TCR_SEP_39 (0x2ULL << ARM_LPAE_TCR_SEP_SHIFT) > >+#define ARM_LPAE_TCR_SEP_41 (0x3ULL << ARM_LPAE_TCR_SEP_SHIFT) > >+#define ARM_LPAE_TCR_SEP_43 (0x4ULL << ARM_LPAE_TCR_SEP_SHIFT) > >+#define ARM_LPAE_TCR_SEP_UPSTREAM (0x7ULL << ARM_LPAE_TCR_SEP_SHIFT) > > This is a specific detail of SMMUv2, and nothing to do with the LPAE/AArch64 > VMSA formats. > > >+ > > #define ARM_LPAE_MAIR_ATTR_SHIFT(n) ((n) << 3) > > #define ARM_LPAE_MAIR_ATTR_MASK 0xff > > #define ARM_LPAE_MAIR_ATTR_DEVICE 0x04 > >@@ -179,11 +195,12 @@ struct arm_lpae_io_pgtable { > > struct io_pgtable iop; > > int levels; > >+ u32 sep; > > size_t pgd_size; > > unsigned long pg_shift; > > unsigned long bits_per_level; > >- void *pgd; > >+ void *pgd[2]; > > }; > > typedef u64 arm_lpae_iopte; > >@@ -426,7 +443,8 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct > >arm_lpae_io_pgtable *data, > > arm_lpae_iopte pte; > > if (data->iop.fmt == ARM_64_LPAE_S1 || > >- data->iop.fmt == ARM_32_LPAE_S1) { > >+ data->iop.fmt == ARM_32_LPAE_S1 || > >+ data->iop.fmt == ARM_64_LPAE_SPLIT_S1) { > > pte = ARM_LPAE_PTE_nG; > > if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) > > pte |= ARM_LPAE_PTE_AP_RDONLY; > >@@ -470,11 +488,10 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct > >arm_lpae_io_pgtable *data, > > return pte; > > } > >-static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, > >- phys_addr_t paddr, size_t size, int iommu_prot) > >+static int _arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long > >iova, > >+ phys_addr_t paddr, size_t size, int iommu_prot, > >+ arm_lpae_iopte *ptep) > > { > >- struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); > >- arm_lpae_iopte *ptep = data->pgd; > > int ret, lvl = ARM_LPAE_START_LVL(data); > > arm_lpae_iopte prot; > >@@ -497,12 +514,39 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, > >unsigned long iova, > > return ret; > > } > >+static int arm_lpae_split_map(struct io_pgtable_ops *ops, unsigned long > >iova, > >+ phys_addr_t paddr, size_t size, int iommu_prot) > >+{ > >+ struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); > >+ unsigned long mask = 1UL << data->sep; > >+ arm_lpae_iopte *ptep; > >+ > >+ if (iova & mask) { > >+ ptep = data->pgd[1]; > >+ iova &= (mask - 1); > >+ } else > >+ ptep = data->pgd[0]; > > AFAICS, this logic effectively aliases the TTBR1 region across the entire > upper half of the address hole, so bogus IOVAs may corrupt valid mappings > instead of giving errors as expected. > > >+ > >+ return _arm_lpae_map(data, iova, paddr, size, iommu_prot, ptep); > >+} > >+ > >+static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, > >+ phys_addr_t paddr, size_t size, int iommu_prot) > >+{ > >+ struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); > >+ > >+ return _arm_lpae_map(data, iova, paddr, size, iommu_prot, data->pgd[0]); > >+} > >+ > > static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int > > lvl, > > arm_lpae_iopte *ptep) > > { > > arm_lpae_iopte *start, *end; > > unsigned long table_size; > >+ if (!ptep) > >+ return; > >+ > > if (lvl == ARM_LPAE_START_LVL(data)) > > table_size = data->pgd_size; > > else > >@@ -532,7 +576,8 @@ static void arm_lpae_free_pgtable(struct io_pgtable *iop) > > { > > struct arm_lpae_io_pgtable *data = io_pgtable_to_data(iop); > >- __arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data), data->pgd); > >+ __arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data), data->pgd[0]); > >+ __arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data), data->pgd[1]); > > kfree(data); > > } > >@@ -643,11 +688,28 @@ static size_t __arm_lpae_unmap(struct > >arm_lpae_io_pgtable *data, > > return __arm_lpae_unmap(data, iova, size, lvl + 1, ptep); > > } > >+static size_t arm_lpae_split_unmap(struct io_pgtable_ops *ops, > >+ unsigned long iova, size_t size) > >+{ > >+ struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); > >+ unsigned long mask = 1UL << data->sep; > >+ arm_lpae_iopte *ptep; > >+ int lvl = ARM_LPAE_START_LVL(data); > >+ > >+ if (iova & mask) { > >+ ptep = data->pgd[1]; > >+ iova &= (mask - 1); > >+ } else > >+ ptep = data->pgd[0]; > >+ > >+ return __arm_lpae_unmap(data, iova, size, lvl, ptep); > >+} > >+ > > static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long > > iova, > > size_t size) > > { > > struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); > >- arm_lpae_iopte *ptep = data->pgd; > >+ arm_lpae_iopte *ptep = data->pgd[0]; > > int lvl = ARM_LPAE_START_LVL(data); > > if (WARN_ON(iova >= (1ULL << data->iop.cfg.ias))) > >@@ -656,11 +718,11 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops > >*ops, unsigned long iova, > > return __arm_lpae_unmap(data, iova, size, lvl, ptep); > > } > >-static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops, > >- unsigned long iova) > >+static phys_addr_t _arm_lpae_iova_to_phys(struct arm_lpae_io_pgtable *data, > >+ unsigned long iova, > >+ arm_lpae_iopte *ptep) > > { > >- struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); > >- arm_lpae_iopte pte, *ptep = data->pgd; > >+ arm_lpae_iopte pte; > > int lvl = ARM_LPAE_START_LVL(data); > > do { > >@@ -692,6 +754,31 @@ static phys_addr_t arm_lpae_iova_to_phys(struct > >io_pgtable_ops *ops, > > return iopte_to_paddr(pte, data) | iova; > > } > >+ > >+static phys_addr_t arm_lpae_split_iova_to_phys(struct io_pgtable_ops *ops, > >+ unsigned long iova) > >+{ > >+ struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); > >+ unsigned long mask = 1UL << data->sep; > >+ arm_lpae_iopte *ptep; > >+ > >+ if (iova & mask) { > >+ ptep = data->pgd[1]; > >+ iova &= (mask - 1); > >+ } else > >+ ptep = data->pgd[0]; > >+ > >+ return _arm_lpae_iova_to_phys(data, iova, ptep); > >+} > >+ > >+static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops, > >+ unsigned long iova) > >+{ > >+ struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); > >+ > >+ return _arm_lpae_iova_to_phys(data, iova, data->pgd[0]); > >+} > >+ > > static void arm_lpae_restrict_pgsizes(struct io_pgtable_cfg *cfg) > > { > > unsigned long granule, page_sizes; > >@@ -771,6 +858,9 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) > > pgd_bits = va_bits - (data->bits_per_level * (data->levels - 1)); > > data->pgd_size = 1UL << (pgd_bits + ilog2(sizeof(arm_lpae_iopte))); > >+ data->pgd[0] = NULL; > >+ data->pgd[1] = NULL; > >+ > > data->iop.ops = (struct io_pgtable_ops) { > > .map = arm_lpae_map, > > .unmap = arm_lpae_unmap, > >@@ -780,8 +870,8 @@ arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg) > > return data; > > } > >-static struct io_pgtable * > >-arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) > >+static struct arm_lpae_io_pgtable * > >+_arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg) > > { > > u64 reg; > > struct arm_lpae_io_pgtable *data; > >@@ -845,8 +935,6 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, > >void *cookie) > > reg |= (64ULL - cfg->ias) << ARM_LPAE_TCR_T0SZ_SHIFT; > >- /* Disable speculative walks through TTBR1 */ > >- reg |= ARM_LPAE_TCR_EPD1; > > Not setting EPD1 at all could potentially lead to problems for systems not > using split tables. > > > cfg->arm_lpae_s1_cfg.tcr = reg; > > /* MAIRs */ > >@@ -863,24 +951,143 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg > >*cfg, void *cookie) > > cfg->arm_lpae_s1_cfg.mair[1] = 0; > > /* Looking good; allocate a pgd */ > >- data->pgd = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg); > >- if (!data->pgd) > >+ data->pgd[0] = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg); > >+ if (!data->pgd[0]) > > goto out_free_data; > > /* Ensure the empty pgd is visible before any actual TTBR write */ > > wmb(); > > /* TTBRs */ > >- cfg->arm_lpae_s1_cfg.ttbr[0] = virt_to_phys(data->pgd); > >+ cfg->arm_lpae_s1_cfg.ttbr[0] = virt_to_phys(data->pgd[0]); > > cfg->arm_lpae_s1_cfg.ttbr[1] = 0; > >+ return data; > >+ > >+out_free_data: > >+ kfree(data); > >+ return NULL; > >+} > >+ > >+ > >+/* Allocate split pagetables */ > >+static struct io_pgtable * > >+arm_64_lpae_alloc_pgtable_split_s1(struct io_pgtable_cfg *cfg, void *cookie) > >+{ > >+ u64 reg; > >+ struct arm_lpae_io_pgtable *data; > >+ u32 sep; > >+ > >+ /* Figure out what the sign extension bit should be */ > >+ switch (cfg->ias) { > > IAS only tells you how wide the SMMU's address input is; what you really > care about for sign extension is how wide the relevant masters' address > *outputs* are. There's no way we can know that here, so AFAICS the only > truly robust answer is for the caller requesting split tables to also > provide the appropriate split point. > > >+ case 32: > >+ case 36: > >+ case 40: > >+ case 42: > >+ case 44: > >+ sep = cfg->ias - 1; > >+ /* Adjust the address size to account for the extension bit */ > >+ cfg->ias--; > >+ break; > >+ case 48: > >+ /* IAS of 48 is a special case, it has a dedicated bit */ > > That's not only not VMSA, but not even any architected SMMU behaviour; it > just happens to be the way that one user of io-pgtable-arm currently mangles > its IAS values. > > Robin. > > >+ sep = 48; > >+ break; > >+ default: > >+ return NULL; > >+ } > >+ > >+ data = _arm_64_lpae_alloc_pgtable_s1(cfg); > >+ if (!data) > >+ return NULL; > >+ > >+ /* Add the TTBR1 settings */ > >+ reg = cfg->arm_lpae_s1_cfg.tcr; > >+ > >+ /* TCR */ > >+ reg |= (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH1_SHIFT) | > >+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN1_SHIFT) | > >+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN1_SHIFT); > >+ > >+ switch (ARM_LPAE_GRANULE(data)) { > >+ case SZ_4K: > >+ reg |= ARM_LPAE_TCR_TG1_4K; > >+ break; > >+ case SZ_16K: > >+ reg |= ARM_LPAE_TCR_TG1_16K; > >+ break; > >+ case SZ_64K: > >+ reg |= ARM_LPAE_TCR_TG1_64K; > >+ break; > >+ } > >+ > >+ reg |= (64ULL - cfg->ias) << ARM_LPAE_TCR_T1SZ_SHIFT; > >+ > >+ switch (sep) { > >+ case 31: > >+ reg |= ARM_LPAE_TCR_SEP_31; > >+ break; > >+ case 35: > >+ reg |= ARM_LPAE_TCR_SEP_35; > >+ break; > >+ case 39: > >+ reg |= ARM_LPAE_TCR_SEP_39; > >+ break; > >+ case 41: > >+ reg |= ARM_LPAE_TCR_SEP_41; > >+ break; > >+ case 43: > >+ reg |= ARM_LPAE_TCR_SEP_43; > >+ break; > >+ case 48: > >+ reg |= ARM_LPAE_TCR_SEP_UPSTREAM; > >+ break; > >+ } > >+ > >+ cfg->arm_lpae_s1_cfg.tcr = reg; > >+ > >+ /* Allocate the TTBR1 pagetable */ > >+ data->pgd[1] = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg); > >+ if (!data->pgd[1]) > >+ goto out_free_data; > >+ > >+ /* Override the data ops with split table specific ops */ > >+ data->iop.ops = (struct io_pgtable_ops) { > >+ .map = arm_lpae_split_map, > >+ .unmap = arm_lpae_split_unmap, > >+ .iova_to_phys = arm_lpae_split_iova_to_phys, > >+ }; > >+ > >+ /* > >+ * remember the sign extension bit, we'll need it later to figure out > >+ * which pagetable to use > >+ */ > >+ data->sep = sep; > >+ > >+ /* Ensure the empty pgd is visible before any actual TTBR write */ > >+ wmb(); > >+ > >+ cfg->arm_lpae_s1_cfg.ttbr[1] = virt_to_phys(data->pgd[1]); > > return &data->iop; > > out_free_data: > >+ __arm_lpae_free_pages(data->pgd[0], data->pgd_size, cfg); > > kfree(data); > > return NULL; > > } > > static struct io_pgtable * > >+arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) > >+{ > >+ struct arm_lpae_io_pgtable *data; > >+ > >+ data = _arm_64_lpae_alloc_pgtable_s1(cfg); > >+ if (!data) > >+ return NULL; > >+ > >+ return &data->iop; > >+} > >+ > >+static struct io_pgtable * > > arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) > > { > > u64 reg, sl; > >@@ -960,15 +1167,15 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg > >*cfg, void *cookie) > > cfg->arm_lpae_s2_cfg.vtcr = reg; > > /* Allocate pgd pages */ > >- data->pgd = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg); > >- if (!data->pgd) > >+ data->pgd[0] = __arm_lpae_alloc_pages(data->pgd_size, GFP_KERNEL, cfg); > >+ if (!data->pgd[0]) > > goto out_free_data; > > /* Ensure the empty pgd is visible before any actual TTBR write */ > > wmb(); > > /* VTTBR */ > >- cfg->arm_lpae_s2_cfg.vttbr = virt_to_phys(data->pgd); > >+ cfg->arm_lpae_s2_cfg.vttbr = virt_to_phys(data->pgd[0]); > > return &data->iop; > > out_free_data: > >@@ -1041,6 +1248,11 @@ struct io_pgtable_init_fns > >io_pgtable_arm_64_lpae_s1_init_fns = { > > .free = arm_lpae_free_pgtable, > > }; > >+struct io_pgtable_init_fns io_pgtable_arm_64_lpae_split_s1_init_fns = { > >+ .alloc = arm_64_lpae_alloc_pgtable_split_s1, > >+ .free = arm_lpae_free_pgtable, > >+}; > >+ > > struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s2_init_fns = { > > .alloc = arm_64_lpae_alloc_pgtable_s2, > > .free = arm_lpae_free_pgtable, > >@@ -1095,9 +1307,9 @@ static void __init arm_lpae_dump_ops(struct > >io_pgtable_ops *ops) > > pr_err("cfg: pgsize_bitmap 0x%lx, ias %u-bit\n", > > cfg->pgsize_bitmap, cfg->ias); > >- pr_err("data: %d levels, 0x%zx pgd_size, %lu pg_shift, %lu > >bits_per_level, pgd @ %p\n", > >+ pr_err("data: %d levels, 0x%zx pgd_size, %lu pg_shift, %lu > >bits_per_level, pgd @ %p %p\n", > > data->levels, data->pgd_size, data->pg_shift, > >- data->bits_per_level, data->pgd); > >+ data->bits_per_level, data->pgd[0], data->pgd[1]); > > } > > #define __FAIL(ops, i) ({ > > \ > >@@ -1112,6 +1324,7 @@ static int __init arm_lpae_run_tests(struct > >io_pgtable_cfg *cfg) > > static const enum io_pgtable_fmt fmts[] = { > > ARM_64_LPAE_S1, > > ARM_64_LPAE_S2, > >+ ARM_64_LPAE_SPLIT_S1, > > }; > > int i, j; > >diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c > >index ced53e5..ed1985f 100644 > >--- a/drivers/iommu/io-pgtable.c > >+++ b/drivers/iommu/io-pgtable.c > >@@ -20,6 +20,7 @@ io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] = { > > [ARM_64_LPAE_S1] = &io_pgtable_arm_64_lpae_s1_init_fns, > > [ARM_64_LPAE_S2] = &io_pgtable_arm_64_lpae_s2_init_fns, > > [ARM_MALI_LPAE] = &io_pgtable_arm_mali_lpae_init_fns, > >+ [ARM_64_LPAE_SPLIT_S1] = &io_pgtable_arm_64_lpae_split_s1_init_fns, > > #endif > > #ifdef CONFIG_IOMMU_IO_PGTABLE_ARMV7S > > [ARM_V7S] = &io_pgtable_arm_v7s_init_fns, > >diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h > >index b5a450a..2ed0e6a 100644 > >--- a/include/linux/io-pgtable.h > >+++ b/include/linux/io-pgtable.h > >@@ -10,6 +10,7 @@ enum io_pgtable_fmt { > > ARM_32_LPAE_S1, > > ARM_32_LPAE_S2, > > ARM_64_LPAE_S1, > >+ ARM_64_LPAE_SPLIT_S1, > > ARM_64_LPAE_S2, > > ARM_V7S, > > ARM_MALI_LPAE, > >@@ -211,6 +212,7 @@ extern struct io_pgtable_init_fns > >io_pgtable_arm_32_lpae_s1_init_fns; > > extern struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s2_init_fns; > > extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns; > > extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s2_init_fns; > >+extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_split_s1_init_fns; > > extern struct io_pgtable_init_fns io_pgtable_arm_v7s_init_fns; > > extern struct io_pgtable_init_fns io_pgtable_arm_mali_lpae_init_fns; > > -- The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project _______________________________________________ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu