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

Commit 6a233e66 authored by Olav Haugan's avatar Olav Haugan
Browse files

iommu: msm: Do not sleep for 10 ms when TLB sync does not complete



TLB sync might take longer than expected to complete and we wait for 10 ms
to recheck. This is causing jitter in some applications. Instead of waiting
too long to check whether TLB sync has completed we use function
readl_tight_poll_timeout to quickly poll the status without incurring sleep
delay.

We also ensure that if we do eventually time out on the TLB sync or iommu
halt we cause a crash to indicate that something has gone wrong.

CRs-fixed: 608971
Change-Id: I6b3e5155ab7aafa80432f95554d25cf0e2b753f9
Signed-off-by: default avatarOlav Haugan <ohaugan@codeaurora.org>
parent cf10ac2f
Loading
Loading
Loading
Loading
+15 −11
Original line number Diff line number Diff line
@@ -15,23 +15,24 @@

#define CTX_SHIFT  12

#define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
#define GET_GLOBAL_REG_Q(reg, base) (readq_relaxed((base) + (reg)))
#define GET_CTX_REG(reg, base, ctx) \
	(readl_relaxed((base) + (reg) + ((ctx) << CTX_SHIFT)))
#define GET_CTX_REG_Q(reg, base, ctx) \
	(readq_relaxed((base) + (reg) + ((ctx) << CTX_SHIFT)))
#define CTX_REG(reg, base, ctx) \
	((base) + (reg) + ((ctx) << CTX_SHIFT))
#define GLB_REG(reg, base) \
	((base) + (reg))

#define GET_GLOBAL_REG(reg, base) (readl_relaxed(GLB_REG(reg, base)))
#define GET_GLOBAL_REG_Q(reg, base) (readq_relaxed(GLB_REG(reg, base)))
#define GET_CTX_REG(reg, base, ctx) (readl_relaxed(CTX_REG(reg, base, ctx)))
#define GET_CTX_REG_Q(reg, base, ctx) (readq_relaxed(CTX_REG(reg, base, ctx)))

#define SET_GLOBAL_REG(reg, base, val)	writel_relaxed((val), ((base) + (reg)))
#define SET_GLOBAL_REG_Q(reg, base, val) \
	(writeq_relaxed((val), ((base) + (reg))))
	(writeq_relaxed((val), GLB_REG(reg, base)))

#define SET_CTX_REG(reg, base, ctx, val) \
	writel_relaxed((val), \
		((base) + (reg) + ((ctx) << CTX_SHIFT)))
	writel_relaxed((val), (CTX_REG(reg, base, ctx)))
#define SET_CTX_REG_Q(reg, base, ctx, val) \
	writeq_relaxed((val), \
		((base) + (reg) + ((ctx) << CTX_SHIFT)))
	writeq_relaxed((val), CTX_REG(reg, base, ctx))

/* Wrappers for numbered registers */
#define SET_GLOBAL_REG_N(b, n, r, v) SET_GLOBAL_REG((b), ((r) + (n << 2)), (v))
@@ -172,6 +173,9 @@ do { \
				GET_GLOBAL_FIELD(b, MICRO_MMU_CTRL, IDLE)
#define SET_MICRO_MMU_CTRL_RESERVED(b, v) \
				SET_GLOBAL_FIELD(b, MICRO_MMU_CTRL, RESERVED, v)

#define MMU_CTRL_IDLE (MICRO_MMU_CTRL_IDLE_MASK << MICRO_MMU_CTRL_IDLE_SHIFT)

#define SET_PREDICTIONDIS0(b, v) SET_GLOBAL_REG(PREDICTIONDIS0, (b), (v))
#define SET_PREDICTIONDIS1(b, v) SET_GLOBAL_REG(PREDICTIONDIS1, (b), (v))
#define SET_S1L1BFBLP0(b, v)     SET_GLOBAL_REG(S1L1BFBLP0, (b), (v))
+22 −16
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/mutex.h>
@@ -174,13 +175,20 @@ struct iommu_access_ops iommu_access_ops_v1 = {
	.iommu_lock_release = _iommu_lock_release,
};

void iommu_halt(const struct msm_iommu_drvdata *iommu_drvdata)
void iommu_halt(struct msm_iommu_drvdata const *iommu_drvdata)
{
	if (iommu_drvdata->halt_enabled) {
		SET_MICRO_MMU_CTRL_HALT_REQ(iommu_drvdata->base, 1);
		unsigned int val;
		void __iomem *base = iommu_drvdata->base;
		int res;

		SET_MICRO_MMU_CTRL_HALT_REQ(base, 1);
		res = readl_tight_poll_timeout(
			GLB_REG(MICRO_MMU_CTRL, base), val,
			     (val & MMU_CTRL_IDLE) == MMU_CTRL_IDLE, 5000000);

		while (GET_MICRO_MMU_CTRL_IDLE(iommu_drvdata->base) == 0)
			cpu_relax();
		if (res)
			BUG();
		/* Ensure device is idle before continuing */
		mb();
	}
@@ -204,21 +212,19 @@ void iommu_resume(const struct msm_iommu_drvdata *iommu_drvdata)
	}
}

static void __sync_tlb(void __iomem *base, int ctx)
static void __sync_tlb(struct msm_iommu_drvdata *iommu_drvdata, int ctx)
{
	int i;
	unsigned int val;
	unsigned int res;
	void __iomem *base = iommu_drvdata->cb_base;

	SET_TLBSYNC(base, ctx, 0);

	/* No barrier needed due to register proximity */
	for (i = 0; i < IOMMU_MSEC_TIMEOUT; i += IOMMU_MSEC_STEP)
		if (GET_CB_TLBSTATUS_SACTIVE(base, ctx) == 0)
			break;
		else
			msleep(IOMMU_MSEC_STEP);

	BUG_ON(i >= IOMMU_MSEC_TIMEOUT);
	/* No barrier needed due to read dependency */
	res = readl_tight_poll_timeout(CTX_REG(CB_TLBSTATUS, base, ctx), val,
				(val & CB_TLBSTATUS_SACTIVE) == 0, 5000000);
	if (res)
		BUG();
}

static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
@@ -242,7 +248,7 @@ static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
		SET_TLBIVA(iommu_drvdata->cb_base, ctx_drvdata->num,
			   ctx_drvdata->asid | (va & CB_TLBIVA_VA));
		mb();
		__sync_tlb(iommu_drvdata->cb_base, ctx_drvdata->num);
		__sync_tlb(iommu_drvdata, ctx_drvdata->num);
		__disable_clocks(iommu_drvdata);
	}
fail:
@@ -269,7 +275,7 @@ static int __flush_iotlb(struct iommu_domain *domain)
		SET_TLBIASID(iommu_drvdata->cb_base, ctx_drvdata->num,
			     ctx_drvdata->asid);
		mb();
		__sync_tlb(iommu_drvdata->cb_base, ctx_drvdata->num);
		__sync_tlb(iommu_drvdata, ctx_drvdata->num);
		__disable_clocks(iommu_drvdata);
	}