summaryrefslogtreecommitdiff
path: root/drivers/iommu/io-pgtable-arm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iommu/io-pgtable-arm.c')
-rw-r--r--drivers/iommu/io-pgtable-arm.c31
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;