Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e62ecb7f authored by Sushmita Susheelendra's avatar Sushmita Susheelendra
Browse files

iommu/arm-smmu: Pass pagefault information to client handlers



Fill out the pagefault flags more fully when calling
client fault handlers so that clients do not have to
read hardware state themselves. Also, respect the -EBUSY
return code from the client by not clearing the FSR or
resuming/terminating the stalled transaction.

Change-Id: I03a2546e8f90a1fa937ccd31bdd062fa05d76adb
Signed-off-by: default avatarSushmita Susheelendra <ssusheel@codeaurora.org>
parent ed0c2194
Loading
Loading
Loading
Loading
+38 −9
Original line number Diff line number Diff line
@@ -923,7 +923,7 @@ static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,

static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
{
	int flags, ret;
	int flags, ret, tmp;
	u32 fsr, fsynr, resume;
	unsigned long iova, far;
	struct iommu_domain *domain = dev;
@@ -966,6 +966,12 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)

	fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0);
	flags = fsynr & FSYNR0_WNR ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ;
	if (fsr & FSR_TF)
		flags |= IOMMU_FAULT_TRANSLATION;
	if (fsr & FSR_PF)
		flags |= IOMMU_FAULT_PERMISSION;
	if (fsr & FSR_SS)
		flags |= IOMMU_FAULT_TRANSACTION_STALLED;

	far = readl_relaxed(cb_base + ARM_SMMU_CB_FAR_LO);
#ifdef CONFIG_64BIT
@@ -975,7 +981,8 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)

	phys_soft = arm_smmu_iova_to_phys(domain, iova);
	frsynra = readl_relaxed(gr1_base + ARM_SMMU_GR1_CBFRSYNRA(cfg->cbndx));
	if (!report_iommu_fault(domain, smmu->dev, iova, flags)) {
	tmp = report_iommu_fault(domain, smmu->dev, iova, flags);
	if (!tmp || (tmp == -EBUSY)) {
		dev_dbg(smmu->dev,
			"Context fault handled by client: iova=0x%08lx, fsr=0x%x, fsynr=0x%x, cb=%d\n",
			iova, fsr, fsynr, cfg->cbndx);
@@ -1005,8 +1012,29 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
		resume = RESUME_TERMINATE;
	}

	/*
	 * If the client returns -EBUSY, do not clear FSR and do not RESUME
	 * if stalled. This is required to keep the IOMMU client stalled on
	 * the outstanding fault. This gives the client a chance to take any
	 * debug action and then terminate the stalled transaction.
	 * So, the sequence in case of stall on fault should be:
	 * 1) Do not clear FSR or write to RESUME here
	 * 2) Client takes any debug action
	 * 3) Client terminates the stalled transaction and resumes the IOMMU
	 * 4) Client clears FSR. The FSR should only be cleared after 3) and
	 *    not before so that the fault remains outstanding. This ensures
	 *    SCTLR.HUPCF has the desired effect if subsequent transactions also
	 *    need to be terminated.
	 */
	if (tmp != -EBUSY) {
		/* Clear the faulting FSR */
	writel(fsr, cb_base + ARM_SMMU_CB_FSR);
		writel_relaxed(fsr, cb_base + ARM_SMMU_CB_FSR);

		/*
		 * Barrier required to ensure that the FSR is cleared
		 * before resuming SMMU operation
		 */
		wmb();

		/* Retry or terminate any stalled transactions */
		if (fsr & FSR_SS) {
@@ -1014,6 +1042,7 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
				arm_smmu_tlb_sync_cb(smmu, cfg->cbndx);
			writel_relaxed(resume, cb_base + ARM_SMMU_CB_RESUME);
		}
	}

	arm_smmu_disable_clocks(smmu);
	mutex_unlock(&smmu_domain->init_mutex);