From cb53a68d6ac6ff0625089c42255cfdc9a5eb713a Mon Sep 17 00:00:00 2001 From: Prakash Gupta Date: Mon, 3 May 2021 09:57:38 +0530 Subject: [PATCH] iommu/arm-smmu: sign extend iova for fault handler The address in the CB's FAR is not sign-extended. With split page tables, this can cause software page table walk causing warning. WARNING: CPU: 2 PID: 264 at drivers/iommu/arm-smmu.c:3161 arm_smmu_iova_to_phys+0xfc/0x128 kgsl kgsl-3d0: CP Illegal instruction error kgsl kgsl-3d0: CP Illegal instruction error kgsl kgsl-3d0: CP Illegal instruction error kgsl kgsl-3d0: CP Illegal instruction error pc : arm_smmu_iova_to_phys+0xfc/0x128 lr : arm_smmu_context_fault+0x188/0xea4 Perform the sign extension in fault handler, as arm_smmu_iova_to_phys() expects the IOVA to be sign extended. Fixes: ff4f34660e98 ("iommu/arm-smmu: Add support for split page table domains") Change-Id: Iced0b7a518dbc27b2770fdae47bedce4e72cc3c1 Signed-off-by: Prakash Gupta --- drivers/iommu/arm-smmu.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 1fa59c6b6cd7..ab1d9c5bc152 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1361,6 +1361,7 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) bool fatal_asf = smmu->options & ARM_SMMU_OPT_FATAL_ASF; phys_addr_t phys_soft; uint64_t pte; + unsigned int ias = smmu_domain->pgtbl_info[0].pgtbl_cfg.ias; bool non_fatal_fault = test_bit(DOMAIN_ATTR_NON_FATAL_FAULTS, smmu_domain->attributes); @@ -1399,6 +1400,16 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) flags |= IOMMU_FAULT_TRANSACTION_STALLED; iova = arm_smmu_cb_readq(smmu, idx, ARM_SMMU_CB_FAR); + + /* + * The address in the CB's FAR is not sign-extended, so lets perform the + * sign extension here, as arm_smmu_iova_to_phys() expects the + * IOVA to be sign extended. + */ + if ((iova & BIT_ULL(ias)) && + (test_bit(DOMAIN_ATTR_SPLIT_TABLES, smmu_domain->attributes))) + iova |= GENMASK_ULL(63, ias + 1); + phys_soft = arm_smmu_iova_to_phys(domain, iova); frsynra = arm_smmu_gr1_read(smmu, ARM_SMMU_GR1_CBFRSYNRA(cfg->cbndx)); tmp = report_iommu_fault(domain, smmu->dev, iova, flags);