Commit db690301 authored by Robin Murphy's avatar Robin Murphy Committed by Will Deacon

iommu/io-pgtable-arm: Prepare for TTBR1 usage

Now that we can correctly extract top-level indices without relying on
the remaining upper bits being zero, the only remaining impediments to
using a given table for TTBR1 are the address validation on map/unmap
and the awkward TCR translation granule format. Add a quirk so that we
can do the right thing at those points.
Tested-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
Signed-off-by: default avatarRobin Murphy <robin.murphy@arm.com>
Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent ac4b80e5
...@@ -104,6 +104,10 @@ ...@@ -104,6 +104,10 @@
#define ARM_LPAE_TCR_TG0_64K 1 #define ARM_LPAE_TCR_TG0_64K 1
#define ARM_LPAE_TCR_TG0_16K 2 #define ARM_LPAE_TCR_TG0_16K 2
#define ARM_LPAE_TCR_TG1_16K 1
#define ARM_LPAE_TCR_TG1_4K 2
#define ARM_LPAE_TCR_TG1_64K 3
#define ARM_LPAE_TCR_SH_NS 0 #define ARM_LPAE_TCR_SH_NS 0
#define ARM_LPAE_TCR_SH_OS 2 #define ARM_LPAE_TCR_SH_OS 2
#define ARM_LPAE_TCR_SH_IS 3 #define ARM_LPAE_TCR_SH_IS 3
...@@ -464,6 +468,7 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, ...@@ -464,6 +468,7 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova,
arm_lpae_iopte *ptep = data->pgd; arm_lpae_iopte *ptep = data->pgd;
int ret, lvl = data->start_level; int ret, lvl = data->start_level;
arm_lpae_iopte prot; arm_lpae_iopte prot;
long iaext = (long)iova >> cfg->ias;
/* If no access, then nothing to do */ /* If no access, then nothing to do */
if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE))) if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
...@@ -472,7 +477,9 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, ...@@ -472,7 +477,9 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova,
if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size)) if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size))
return -EINVAL; return -EINVAL;
if (WARN_ON(iova >> data->iop.cfg.ias || paddr >> data->iop.cfg.oas)) if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1)
iaext = ~iaext;
if (WARN_ON(iaext || paddr >> cfg->oas))
return -ERANGE; return -ERANGE;
prot = arm_lpae_prot_to_pte(data, iommu_prot); prot = arm_lpae_prot_to_pte(data, iommu_prot);
...@@ -638,11 +645,14 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova, ...@@ -638,11 +645,14 @@ static size_t arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops); struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
struct io_pgtable_cfg *cfg = &data->iop.cfg; struct io_pgtable_cfg *cfg = &data->iop.cfg;
arm_lpae_iopte *ptep = data->pgd; arm_lpae_iopte *ptep = data->pgd;
long iaext = (long)iova >> cfg->ias;
if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size)) if (WARN_ON(!size || (size & cfg->pgsize_bitmap) != size))
return 0; return 0;
if (WARN_ON(iova >> data->iop.cfg.ias)) if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1)
iaext = ~iaext;
if (WARN_ON(iaext))
return 0; return 0;
return __arm_lpae_unmap(data, gather, iova, size, data->start_level, ptep); return __arm_lpae_unmap(data, gather, iova, size, data->start_level, ptep);
...@@ -778,9 +788,11 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) ...@@ -778,9 +788,11 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
u64 reg; u64 reg;
struct arm_lpae_io_pgtable *data; struct arm_lpae_io_pgtable *data;
typeof(&cfg->arm_lpae_s1_cfg.tcr) tcr = &cfg->arm_lpae_s1_cfg.tcr; typeof(&cfg->arm_lpae_s1_cfg.tcr) tcr = &cfg->arm_lpae_s1_cfg.tcr;
bool tg1;
if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS | if (cfg->quirks & ~(IO_PGTABLE_QUIRK_ARM_NS |
IO_PGTABLE_QUIRK_NON_STRICT)) IO_PGTABLE_QUIRK_NON_STRICT |
IO_PGTABLE_QUIRK_ARM_TTBR1))
return NULL; return NULL;
data = arm_lpae_alloc_pgtable(cfg); data = arm_lpae_alloc_pgtable(cfg);
...@@ -798,15 +810,16 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) ...@@ -798,15 +810,16 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
tcr->orgn = ARM_LPAE_TCR_RGN_NC; tcr->orgn = ARM_LPAE_TCR_RGN_NC;
} }
tg1 = cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1;
switch (ARM_LPAE_GRANULE(data)) { switch (ARM_LPAE_GRANULE(data)) {
case SZ_4K: case SZ_4K:
tcr->tg = ARM_LPAE_TCR_TG0_4K; tcr->tg = tg1 ? ARM_LPAE_TCR_TG1_4K : ARM_LPAE_TCR_TG0_4K;
break; break;
case SZ_16K: case SZ_16K:
tcr->tg = ARM_LPAE_TCR_TG0_16K; tcr->tg = tg1 ? ARM_LPAE_TCR_TG1_16K : ARM_LPAE_TCR_TG0_16K;
break; break;
case SZ_64K: case SZ_64K:
tcr->tg = ARM_LPAE_TCR_TG0_64K; tcr->tg = tg1 ? ARM_LPAE_TCR_TG1_64K : ARM_LPAE_TCR_TG0_64K;
break; break;
} }
......
...@@ -83,12 +83,16 @@ struct io_pgtable_cfg { ...@@ -83,12 +83,16 @@ struct io_pgtable_cfg {
* IO_PGTABLE_QUIRK_NON_STRICT: Skip issuing synchronous leaf TLBIs * IO_PGTABLE_QUIRK_NON_STRICT: Skip issuing synchronous leaf TLBIs
* on unmap, for DMA domains using the flush queue mechanism for * on unmap, for DMA domains using the flush queue mechanism for
* delayed invalidation. * delayed invalidation.
*
* IO_PGTABLE_QUIRK_ARM_TTBR1: (ARM LPAE format) Configure the table
* for use in the upper half of a split address space.
*/ */
#define IO_PGTABLE_QUIRK_ARM_NS BIT(0) #define IO_PGTABLE_QUIRK_ARM_NS BIT(0)
#define IO_PGTABLE_QUIRK_NO_PERMS BIT(1) #define IO_PGTABLE_QUIRK_NO_PERMS BIT(1)
#define IO_PGTABLE_QUIRK_TLBI_ON_MAP BIT(2) #define IO_PGTABLE_QUIRK_TLBI_ON_MAP BIT(2)
#define IO_PGTABLE_QUIRK_ARM_MTK_EXT BIT(3) #define IO_PGTABLE_QUIRK_ARM_MTK_EXT BIT(3)
#define IO_PGTABLE_QUIRK_NON_STRICT BIT(4) #define IO_PGTABLE_QUIRK_NON_STRICT BIT(4)
#define IO_PGTABLE_QUIRK_ARM_TTBR1 BIT(5)
unsigned long quirks; unsigned long quirks;
unsigned long pgsize_bitmap; unsigned long pgsize_bitmap;
unsigned int ias; unsigned int ias;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment