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 <guptap@codeaurora.org>
This commit is contained in:
Prakash Gupta 2020-12-22 16:38:13 +05:30
commit da907495ce

View file

@ -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: