diff options
Diffstat (limited to 'drivers/iommu/io-pgtable-arm.c')
-rw-r--r-- | drivers/iommu/io-pgtable-arm.c | 31 |
1 files changed, 20 insertions, 11 deletions
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 2d2583c78bdb..7651545e3f2e 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -550,9 +550,18 @@ static inline arm_lpae_iopte *arm_lpae_get_table( { struct io_pgtable_cfg *cfg = &data->iop.cfg; - return ((cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1) && - (iova & (1UL << (cfg->ias - 1)))) ? - data->pgd[1] : data->pgd[0]; + /* + * iovas for TTBR1 will have all the bits set between the input address + * region and the sign extension bit + */ + if (unlikely(cfg->quirks & IO_PGTABLE_QUIRK_ARM_TTBR1)) { + unsigned long mask = GENMASK(cfg->sep, cfg->ias); + + if ((iova & mask) == mask) + return data->pgd[1]; + } + + return data->pgd[0]; } static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova, @@ -1089,26 +1098,26 @@ static u64 arm64_lpae_setup_ttbr1(struct io_pgtable_cfg *cfg, /* Set T1SZ */ reg |= (64ULL - cfg->ias) << ARM_LPAE_TCR_T1SZ_SHIFT; - /* Set the SEP bit based on the size */ - switch (cfg->ias) { - case 32: + switch (cfg->sep) { + case 31: reg |= (ARM_LPAE_TCR_SEP_31 << ARM_LPAE_TCR_SEP_SHIFT); break; - case 36: + case 35: reg |= (ARM_LPAE_TCR_SEP_35 << ARM_LPAE_TCR_SEP_SHIFT); break; - case 40: + case 39: reg |= (ARM_LPAE_TCR_SEP_39 << ARM_LPAE_TCR_SEP_SHIFT); break; - case 42: + case 41: reg |= (ARM_LPAE_TCR_SEP_41 << ARM_LPAE_TCR_SEP_SHIFT); break; - case 44: + case 43: reg |= (ARM_LPAE_TCR_SEP_43 << ARM_LPAE_TCR_SEP_SHIFT); break; - case 48: + case 47: reg |= (ARM_LPAE_TCR_SEP_47 << ARM_LPAE_TCR_SEP_SHIFT); break; + case 48: default: reg |= (ARM_LPAE_TCR_SEP_UPSTREAM << ARM_LPAE_TCR_SEP_SHIFT); break; |