Commit ac4b80e5 authored by Will Deacon's avatar Will Deacon

iommu/io-pgtable-arm: Rationalise VTCR handling

Commit 05a648cd2dd7 ("iommu/io-pgtable-arm: Rationalise TCR handling")
reworked the way in which the TCR register value is returned from the
io-pgtable code when targetting the Arm long-descriptor format, in
preparation for allowing page-tables to target TTBR1.

As it turns out, the new interface is a lot nicer to use, so do the same
conversion for the VTCR register even though there is only a single base
register for stage-2 translation.

Cc: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent fba6e960
...@@ -250,6 +250,13 @@ ...@@ -250,6 +250,13 @@
#define STRTAB_STE_2_S2VMID GENMASK_ULL(15, 0) #define STRTAB_STE_2_S2VMID GENMASK_ULL(15, 0)
#define STRTAB_STE_2_VTCR GENMASK_ULL(50, 32) #define STRTAB_STE_2_VTCR GENMASK_ULL(50, 32)
#define STRTAB_STE_2_VTCR_S2T0SZ GENMASK_ULL(5, 0)
#define STRTAB_STE_2_VTCR_S2SL0 GENMASK_ULL(7, 6)
#define STRTAB_STE_2_VTCR_S2IR0 GENMASK_ULL(9, 8)
#define STRTAB_STE_2_VTCR_S2OR0 GENMASK_ULL(11, 10)
#define STRTAB_STE_2_VTCR_S2SH0 GENMASK_ULL(13, 12)
#define STRTAB_STE_2_VTCR_S2TG GENMASK_ULL(15, 14)
#define STRTAB_STE_2_VTCR_S2PS GENMASK_ULL(18, 16)
#define STRTAB_STE_2_S2AA64 (1UL << 51) #define STRTAB_STE_2_S2AA64 (1UL << 51)
#define STRTAB_STE_2_S2ENDI (1UL << 52) #define STRTAB_STE_2_S2ENDI (1UL << 52)
#define STRTAB_STE_2_S2PTW (1UL << 54) #define STRTAB_STE_2_S2PTW (1UL << 54)
...@@ -2159,14 +2166,22 @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain, ...@@ -2159,14 +2166,22 @@ static int arm_smmu_domain_finalise_s2(struct arm_smmu_domain *smmu_domain,
int vmid; int vmid;
struct arm_smmu_device *smmu = smmu_domain->smmu; struct arm_smmu_device *smmu = smmu_domain->smmu;
struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg; struct arm_smmu_s2_cfg *cfg = &smmu_domain->s2_cfg;
typeof(&pgtbl_cfg->arm_lpae_s2_cfg.vtcr) vtcr;
vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits); vmid = arm_smmu_bitmap_alloc(smmu->vmid_map, smmu->vmid_bits);
if (vmid < 0) if (vmid < 0)
return vmid; return vmid;
vtcr = &pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
cfg->vmid = (u16)vmid; cfg->vmid = (u16)vmid;
cfg->vttbr = pgtbl_cfg->arm_lpae_s2_cfg.vttbr; cfg->vttbr = pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
cfg->vtcr = pgtbl_cfg->arm_lpae_s2_cfg.vtcr; cfg->vtcr = FIELD_PREP(STRTAB_STE_2_VTCR_S2T0SZ, vtcr->tsz) |
FIELD_PREP(STRTAB_STE_2_VTCR_S2SL0, vtcr->sl) |
FIELD_PREP(STRTAB_STE_2_VTCR_S2IR0, vtcr->irgn) |
FIELD_PREP(STRTAB_STE_2_VTCR_S2OR0, vtcr->orgn) |
FIELD_PREP(STRTAB_STE_2_VTCR_S2SH0, vtcr->sh) |
FIELD_PREP(STRTAB_STE_2_VTCR_S2TG, vtcr->tg) |
FIELD_PREP(STRTAB_STE_2_VTCR_S2PS, vtcr->ps);
return 0; return 0;
} }
......
...@@ -548,7 +548,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, ...@@ -548,7 +548,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
cb->tcr[0] |= ARM_SMMU_TCR_EAE; cb->tcr[0] |= ARM_SMMU_TCR_EAE;
} }
} else { } else {
cb->tcr[0] = pgtbl_cfg->arm_lpae_s2_cfg.vtcr; cb->tcr[0] = arm_smmu_lpae_vtcr(pgtbl_cfg);
} }
/* TTBRs */ /* TTBRs */
......
...@@ -174,6 +174,15 @@ enum arm_smmu_cbar_type { ...@@ -174,6 +174,15 @@ enum arm_smmu_cbar_type {
#define ARM_SMMU_TCR_IRGN0 GENMASK(9, 8) #define ARM_SMMU_TCR_IRGN0 GENMASK(9, 8)
#define ARM_SMMU_TCR_T0SZ GENMASK(5, 0) #define ARM_SMMU_TCR_T0SZ GENMASK(5, 0)
#define ARM_SMMU_VTCR_RES1 BIT(31)
#define ARM_SMMU_VTCR_PS GENMASK(18, 16)
#define ARM_SMMU_VTCR_TG0 ARM_SMMU_TCR_TG0
#define ARM_SMMU_VTCR_SH0 ARM_SMMU_TCR_SH0
#define ARM_SMMU_VTCR_ORGN0 ARM_SMMU_TCR_ORGN0
#define ARM_SMMU_VTCR_IRGN0 ARM_SMMU_TCR_IRGN0
#define ARM_SMMU_VTCR_SL0 GENMASK(7, 6)
#define ARM_SMMU_VTCR_T0SZ ARM_SMMU_TCR_T0SZ
#define ARM_SMMU_CB_CONTEXTIDR 0x34 #define ARM_SMMU_CB_CONTEXTIDR 0x34
#define ARM_SMMU_CB_S1_MAIR0 0x38 #define ARM_SMMU_CB_S1_MAIR0 0x38
#define ARM_SMMU_CB_S1_MAIR1 0x3c #define ARM_SMMU_CB_S1_MAIR1 0x3c
...@@ -352,6 +361,18 @@ static inline u32 arm_smmu_lpae_tcr2(struct io_pgtable_cfg *cfg) ...@@ -352,6 +361,18 @@ static inline u32 arm_smmu_lpae_tcr2(struct io_pgtable_cfg *cfg)
FIELD_PREP(ARM_SMMU_TCR2_SEP, ARM_SMMU_TCR2_SEP_UPSTREAM); FIELD_PREP(ARM_SMMU_TCR2_SEP, ARM_SMMU_TCR2_SEP_UPSTREAM);
} }
static inline u32 arm_smmu_lpae_vtcr(struct io_pgtable_cfg *cfg)
{
return ARM_SMMU_VTCR_RES1 |
FIELD_PREP(ARM_SMMU_VTCR_PS, cfg->arm_lpae_s2_cfg.vtcr.ps) |
FIELD_PREP(ARM_SMMU_VTCR_TG0, cfg->arm_lpae_s2_cfg.vtcr.tg) |
FIELD_PREP(ARM_SMMU_VTCR_SH0, cfg->arm_lpae_s2_cfg.vtcr.sh) |
FIELD_PREP(ARM_SMMU_VTCR_ORGN0, cfg->arm_lpae_s2_cfg.vtcr.orgn) |
FIELD_PREP(ARM_SMMU_VTCR_IRGN0, cfg->arm_lpae_s2_cfg.vtcr.irgn) |
FIELD_PREP(ARM_SMMU_VTCR_SL0, cfg->arm_lpae_s2_cfg.vtcr.sl) |
FIELD_PREP(ARM_SMMU_VTCR_T0SZ, cfg->arm_lpae_s2_cfg.vtcr.tsz);
}
/* Implementation details, yay! */ /* Implementation details, yay! */
struct arm_smmu_impl { struct arm_smmu_impl {
u32 (*read_reg)(struct arm_smmu_device *smmu, int page, int offset); u32 (*read_reg)(struct arm_smmu_device *smmu, int page, int offset);
......
...@@ -100,26 +100,19 @@ ...@@ -100,26 +100,19 @@
#define ARM_LPAE_PTE_MEMATTR_DEV (((arm_lpae_iopte)0x1) << 2) #define ARM_LPAE_PTE_MEMATTR_DEV (((arm_lpae_iopte)0x1) << 2)
/* Register bits */ /* Register bits */
#define ARM_64_LPAE_VTCR_RES1 (1U << 31)
#define ARM_LPAE_VTCR_TG0_SHIFT 14
#define ARM_LPAE_TCR_TG0_4K 0 #define ARM_LPAE_TCR_TG0_4K 0
#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_SH0_SHIFT 12
#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
#define ARM_LPAE_TCR_ORGN0_SHIFT 10
#define ARM_LPAE_TCR_IRGN0_SHIFT 8
#define ARM_LPAE_TCR_RGN_NC 0 #define ARM_LPAE_TCR_RGN_NC 0
#define ARM_LPAE_TCR_RGN_WBWA 1 #define ARM_LPAE_TCR_RGN_WBWA 1
#define ARM_LPAE_TCR_RGN_WT 2 #define ARM_LPAE_TCR_RGN_WT 2
#define ARM_LPAE_TCR_RGN_WB 3 #define ARM_LPAE_TCR_RGN_WB 3
#define ARM_LPAE_VTCR_SL0_SHIFT 6
#define ARM_LPAE_VTCR_SL0_MASK 0x3 #define ARM_LPAE_VTCR_SL0_MASK 0x3
#define ARM_LPAE_TCR_T0SZ_SHIFT 0 #define ARM_LPAE_TCR_T0SZ_SHIFT 0
...@@ -878,8 +871,9 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) ...@@ -878,8 +871,9 @@ arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
static struct io_pgtable * static struct io_pgtable *
arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
{ {
u64 reg, sl; u64 sl;
struct arm_lpae_io_pgtable *data; struct arm_lpae_io_pgtable *data;
typeof(&cfg->arm_lpae_s2_cfg.vtcr) vtcr = &cfg->arm_lpae_s2_cfg.vtcr;
/* The NS quirk doesn't apply at stage 2 */ /* The NS quirk doesn't apply at stage 2 */
if (cfg->quirks & ~(IO_PGTABLE_QUIRK_NON_STRICT)) if (cfg->quirks & ~(IO_PGTABLE_QUIRK_NON_STRICT))
...@@ -904,61 +898,59 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) ...@@ -904,61 +898,59 @@ arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
} }
/* VTCR */ /* VTCR */
reg = ARM_64_LPAE_VTCR_RES1;
if (cfg->coherent_walk) { if (cfg->coherent_walk) {
reg |= (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) | vtcr->sh = ARM_LPAE_TCR_SH_IS;
(ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) | vtcr->irgn = ARM_LPAE_TCR_RGN_WBWA;
(ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT); vtcr->orgn = ARM_LPAE_TCR_RGN_WBWA;
} else { } else {
reg |= (ARM_LPAE_TCR_SH_OS << ARM_LPAE_TCR_SH0_SHIFT) | vtcr->sh = ARM_LPAE_TCR_SH_OS;
(ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_IRGN0_SHIFT) | vtcr->irgn = ARM_LPAE_TCR_RGN_NC;
(ARM_LPAE_TCR_RGN_NC << ARM_LPAE_TCR_ORGN0_SHIFT); vtcr->orgn = ARM_LPAE_TCR_RGN_NC;
} }
sl = data->start_level; sl = data->start_level;
switch (ARM_LPAE_GRANULE(data)) { switch (ARM_LPAE_GRANULE(data)) {
case SZ_4K: case SZ_4K:
reg |= (ARM_LPAE_TCR_TG0_4K << ARM_LPAE_VTCR_TG0_SHIFT); vtcr->tg = ARM_LPAE_TCR_TG0_4K;
sl++; /* SL0 format is different for 4K granule size */ sl++; /* SL0 format is different for 4K granule size */
break; break;
case SZ_16K: case SZ_16K:
reg |= (ARM_LPAE_TCR_TG0_16K << ARM_LPAE_VTCR_TG0_SHIFT); vtcr->tg = ARM_LPAE_TCR_TG0_16K;
break; break;
case SZ_64K: case SZ_64K:
reg |= (ARM_LPAE_TCR_TG0_64K << ARM_LPAE_VTCR_TG0_SHIFT); vtcr->tg = ARM_LPAE_TCR_TG0_64K;
break; break;
} }
switch (cfg->oas) { switch (cfg->oas) {
case 32: case 32:
reg |= (ARM_LPAE_TCR_PS_32_BIT << ARM_LPAE_VTCR_PS_SHIFT); vtcr->ps = ARM_LPAE_TCR_PS_32_BIT;
break; break;
case 36: case 36:
reg |= (ARM_LPAE_TCR_PS_36_BIT << ARM_LPAE_VTCR_PS_SHIFT); vtcr->ps = ARM_LPAE_TCR_PS_36_BIT;
break; break;
case 40: case 40:
reg |= (ARM_LPAE_TCR_PS_40_BIT << ARM_LPAE_VTCR_PS_SHIFT); vtcr->ps = ARM_LPAE_TCR_PS_40_BIT;
break; break;
case 42: case 42:
reg |= (ARM_LPAE_TCR_PS_42_BIT << ARM_LPAE_VTCR_PS_SHIFT); vtcr->ps = ARM_LPAE_TCR_PS_42_BIT;
break; break;
case 44: case 44:
reg |= (ARM_LPAE_TCR_PS_44_BIT << ARM_LPAE_VTCR_PS_SHIFT); vtcr->ps = ARM_LPAE_TCR_PS_44_BIT;
break; break;
case 48: case 48:
reg |= (ARM_LPAE_TCR_PS_48_BIT << ARM_LPAE_VTCR_PS_SHIFT); vtcr->ps = ARM_LPAE_TCR_PS_48_BIT;
break; break;
case 52: case 52:
reg |= (ARM_LPAE_TCR_PS_52_BIT << ARM_LPAE_VTCR_PS_SHIFT); vtcr->ps = ARM_LPAE_TCR_PS_52_BIT;
break; break;
default: default:
goto out_free_data; goto out_free_data;
} }
reg |= (64ULL - cfg->ias) << ARM_LPAE_TCR_T0SZ_SHIFT; vtcr->tsz = 64ULL - cfg->ias;
reg |= (~sl & ARM_LPAE_VTCR_SL0_MASK) << ARM_LPAE_VTCR_SL0_SHIFT; vtcr->sl = ~sl & ARM_LPAE_VTCR_SL0_MASK;
cfg->arm_lpae_s2_cfg.vtcr = reg;
/* Allocate pgd pages */ /* Allocate pgd pages */
data->pgd = __arm_lpae_alloc_pages(ARM_LPAE_PGD_SIZE(data), data->pgd = __arm_lpae_alloc_pages(ARM_LPAE_PGD_SIZE(data),
...@@ -985,24 +977,17 @@ arm_32_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie) ...@@ -985,24 +977,17 @@ arm_32_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
return NULL; return NULL;
cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G); cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G);
return arm_64_lpae_alloc_pgtable_s1(cfg, cookie); return arm_64_lpae_alloc_pgtable_s1(cfg, cookie);
} }
static struct io_pgtable * static struct io_pgtable *
arm_32_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) arm_32_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
{ {
struct io_pgtable *iop;
if (cfg->ias > 40 || cfg->oas > 40) if (cfg->ias > 40 || cfg->oas > 40)
return NULL; return NULL;
cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G); cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G);
iop = arm_64_lpae_alloc_pgtable_s2(cfg, cookie); return arm_64_lpae_alloc_pgtable_s2(cfg, cookie);
if (iop)
cfg->arm_lpae_s2_cfg.vtcr &= 0xffffffff;
return iop;
} }
static struct io_pgtable * static struct io_pgtable *
......
...@@ -114,7 +114,15 @@ struct io_pgtable_cfg { ...@@ -114,7 +114,15 @@ struct io_pgtable_cfg {
struct { struct {
u64 vttbr; u64 vttbr;
u64 vtcr; struct {
u32 ps:3;
u32 tg:2;
u32 sh:2;
u32 orgn:2;
u32 irgn:2;
u32 sl:2;
u32 tsz:6;
} vtcr;
} arm_lpae_s2_cfg; } arm_lpae_s2_cfg;
struct { struct {
......
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