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

Commit 690ea2d6 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

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

parents a820922f e62ecb7f
Loading
Loading
Loading
Loading
+38 −9
Original line number Diff line number Diff line
@@ -935,7 +935,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;
@@ -978,6 +978,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
@@ -987,7 +993,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);
@@ -1017,8 +1024,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) {
@@ -1026,6 +1054,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);
+10 −2
Original line number Diff line number Diff line
@@ -39,8 +39,11 @@ struct iommu_domain;
struct notifier_block;

/* iommu fault flags */
#define IOMMU_FAULT_READ	0x0
#define IOMMU_FAULT_WRITE	0x1
#define IOMMU_FAULT_READ                (1 << 0)
#define IOMMU_FAULT_WRITE               (1 << 1)
#define IOMMU_FAULT_TRANSLATION         (1 << 2)
#define IOMMU_FAULT_PERMISSION          (1 << 3)
#define IOMMU_FAULT_TRANSACTION_STALLED (1 << 4)

typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
			struct device *, unsigned long, int, void *);
@@ -250,6 +253,11 @@ extern void iommu_domain_window_disable(struct iommu_domain *domain, u32 wnd_nr)
 * Specifically, -ENOSYS is returned if a fault handler isn't installed
 * (though fault handlers can also return -ENOSYS, in case they want to
 * elicit the default behavior of the IOMMU drivers).

 * Client fault handler returns -EBUSY to signal to the IOMMU driver
 * that the client will take responsibility for any further fault
 * handling, including clearing fault status registers or retrying
 * the faulting transaction.
 */
static inline int report_iommu_fault(struct iommu_domain *domain,
		struct device *dev, unsigned long iova, int flags)