From da907495ce1fbea0c043e0d1d1b9ef69afa626ed Mon Sep 17 00:00:00 2001 From: Prakash Gupta Date: Tue, 22 Dec 2020 16:38:13 +0530 Subject: [PATCH] iommu/arm-smmu: fix out of bound iova fault handling qsmmuv500_iova_to_phys checks for out of bound iova and skips ECATS operations. While this is optimal, this also skips resuming stalled CB. As part of S1 context fault handling iova_to_phys is followed by tlb invalidation and sync. With context bank in stall state, the sync operation will timeout. Example: arm-smmu: FAR = 0x000102325429beb4 arm-smmu: PAR = 0x0000000000000000 arm-smmu: FSR = 0x40000402 [TF R SS ] arm-smmu: ECATS: address out of bounds: 0x000102325429beb4 arm-smmu: ECATS: address out of bounds: 0x000102325429beb4 arm-smmu: TLB sync timed out -- SMMU may be deadlocked Call trace: qsmmuv500_tlb_sync_timeout+0x360 __arm_smmu_tlb_sync+0x2b4 arm_smmu_tlb_sync_context+0x4c arm_smmu_tlb_inv_context_s1+0x1ec arm_smmu_context_fault+0xb84 irq_thread_fn+0x44 irq_thread+0x160 kthread+0x16c ret_from_fork+0x10 Fix this by resuming the context bank before bailing out for out of bound iova. Change-Id: I754b38a3761869a5f0c00688211d26f1b0f47eec Signed-off-by: Prakash Gupta --- drivers/iommu/arm-smmu-qcom.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/iommu/arm-smmu-qcom.c b/drivers/iommu/arm-smmu-qcom.c index 142e4f6aa5fe..d606a7de8e78 100644 --- a/drivers/iommu/arm-smmu-qcom.c +++ b/drivers/iommu/arm-smmu-qcom.c @@ -1388,7 +1388,6 @@ static struct qsmmuv500_tbu_device *qsmmuv500_find_tbu( static int qsmmuv500_ecats_lock(struct arm_smmu_domain *smmu_domain, struct qsmmuv500_tbu_device *tbu, unsigned long *flags) - __acquires(&smmu->atos_lock) { struct arm_smmu_device *smmu = tbu->smmu; struct qsmmuv500_archdata *data = to_qsmmuv500_archdata(smmu); @@ -1413,7 +1412,6 @@ static int qsmmuv500_ecats_lock(struct arm_smmu_domain *smmu_domain, static void qsmmuv500_ecats_unlock(struct arm_smmu_domain *smmu_domain, struct qsmmuv500_tbu_device *tbu, unsigned long *flags) - __releases(&smmu->atos_lock) { struct arm_smmu_device *smmu = tbu->smmu; struct qsmmuv500_archdata *data = to_qsmmuv500_archdata(smmu); @@ -1449,12 +1447,6 @@ static phys_addr_t qsmmuv500_iova_to_phys( if (iova_ext_bits && split_tables) iova_ext_bits = ~iova_ext_bits; - if (iova_ext_bits) { - dev_err_ratelimited(smmu->dev, "ECATS: address out of bounds: %pad\n", - &iova); - return 0; - } - tbu = qsmmuv500_find_tbu(smmu, sid); if (!tbu) return 0; @@ -1494,6 +1486,15 @@ static phys_addr_t qsmmuv500_iova_to_phys( RESUME_TERMINATE); } + /* checking out of bound fault after resuming stalled transactions */ + if (iova_ext_bits) { + dev_err_ratelimited(smmu->dev, + "ECATS: address out of bounds: %pad\n", + &iova); + goto out_resume; + } + + /* Only one concurrent atos operation */ ret = qsmmuv500_ecats_lock(smmu_domain, tbu, &flags); if (ret) @@ -1587,10 +1588,10 @@ redo: if (!phys && needs_redo++ < 2) goto redo; - arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, sctlr_orig); qsmmuv500_ecats_unlock(smmu_domain, tbu, &flags); out_resume: + arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, sctlr_orig); qsmmuv500_tbu_resume(tbu); out_power_off: