forked from rubenslte/android_kernel_samsung_msm8226
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: Olav Haugan <ohaugan@codeaurora.org>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@@ -16,17 +16,19 @@
|
||||
#define CTX_SHIFT 12
|
||||
#define CTX_OFFSET 0x8000
|
||||
|
||||
#define GET_GLOBAL_REG(reg, base) (readl_relaxed((base) + (reg)))
|
||||
#define GET_CTX_REG(reg, base, ctx) \
|
||||
(readl_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
|
||||
#define GET_CTX_REG_L(reg, base, ctx) \
|
||||
(readll_relaxed((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
|
||||
#define CTX_REG(reg, base, ctx) \
|
||||
((base) + CTX_OFFSET + (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_CTX_REG(reg, base, ctx) (readl_relaxed(CTX_REG(reg, base, ctx)))
|
||||
#define GET_CTX_REG_L(reg, base, ctx) (readll_relaxed(CTX_REG(reg, base, ctx)))
|
||||
|
||||
#define SET_GLOBAL_REG(reg, base, val) writel_relaxed((val), ((base) + (reg)))
|
||||
|
||||
#define SET_CTX_REG(reg, base, ctx, val) \
|
||||
writel_relaxed((val), \
|
||||
((base) + CTX_OFFSET + (reg) + ((ctx) << CTX_SHIFT)))
|
||||
writel_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))
|
||||
@@ -150,6 +152,11 @@ do { \
|
||||
SET_GLOBAL_FIELD(b, MICRO_MMU_CTRL, HALT_REQ, v)
|
||||
#define GET_MICRO_MMU_CTRL_IDLE(b) \
|
||||
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))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
@@ -16,6 +16,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>
|
||||
@@ -143,13 +144,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;
|
||||
|
||||
while (GET_MICRO_MMU_CTRL_IDLE(iommu_drvdata->base) == 0)
|
||||
cpu_relax();
|
||||
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);
|
||||
|
||||
if (res)
|
||||
BUG();
|
||||
/* Ensure device is idle before continuing */
|
||||
mb();
|
||||
}
|
||||
@@ -173,15 +181,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)
|
||||
{
|
||||
unsigned int val;
|
||||
unsigned int res;
|
||||
void __iomem *base = iommu_drvdata->base;
|
||||
|
||||
SET_TLBSYNC(base, ctx, 0);
|
||||
|
||||
/* No barrier needed due to register proximity */
|
||||
while (GET_CB_TLBSTATUS_SACTIVE(base, ctx))
|
||||
cpu_relax();
|
||||
|
||||
/* 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)
|
||||
@@ -205,7 +217,7 @@ static int __flush_iotlb_va(struct iommu_domain *domain, unsigned int va)
|
||||
SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
|
||||
ctx_drvdata->asid | (va & CB_TLBIVA_VA));
|
||||
mb();
|
||||
__sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
|
||||
__sync_tlb(iommu_drvdata, ctx_drvdata->num);
|
||||
__disable_clocks(iommu_drvdata);
|
||||
}
|
||||
fail:
|
||||
@@ -232,7 +244,7 @@ static int __flush_iotlb(struct iommu_domain *domain)
|
||||
SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num,
|
||||
ctx_drvdata->asid);
|
||||
mb();
|
||||
__sync_tlb(iommu_drvdata->base, ctx_drvdata->num);
|
||||
__sync_tlb(iommu_drvdata, ctx_drvdata->num);
|
||||
__disable_clocks(iommu_drvdata);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user