Merge "iommu: msm: Do not sleep for 10 ms when TLB sync does not complete"
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
index 04cd441..4509092 100644
--- a/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
+++ b/arch/arm/mach-msm/include/mach/iommu_hw-v1.h
@@ -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 @@
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))
diff --git a/drivers/iommu/msm_iommu-v1.c b/drivers/iommu/msm_iommu-v1.c
index 84f81bf..827225b 100644
--- a/drivers/iommu/msm_iommu-v1.c
+++ b/drivers/iommu/msm_iommu-v1.c
@@ -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 @@
.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 @@
}
}
-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 @@
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 @@
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);
}