Initial Contribution
msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142
Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index bc0e1d8..b6850fe 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -23,6 +23,14 @@
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+#include <asm/io.h>
+#include <mach/msm_iomap.h>
+#endif
+
+#ifdef CONFIG_EMULATE_DOMAIN_MANAGER_V7
+#include <asm/domain.h>
+#endif /* CONFIG_EMULATE_DOMAIN_MANAGER_V7 */
#include "fault.h"
@@ -484,6 +492,49 @@
return 1;
}
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+#define __str(x) #x
+#define MRC(x, v1, v2, v4, v5, v6) do { \
+ unsigned int __##x; \
+ asm("mrc " __str(v1) ", " __str(v2) ", %0, " __str(v4) ", " \
+ __str(v5) ", " __str(v6) "\n" \
+ : "=r" (__##x)); \
+ pr_info("%s: %s = 0x%.8x\n", __func__, #x, __##x); \
+} while(0)
+
+#define MSM_TCSR_SPARE2 (MSM_TCSR_BASE + 0x60)
+
+#endif
+
+static int
+do_imprecise_ext(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+ MRC(ADFSR, p15, 0, c5, c1, 0);
+ MRC(DFSR, p15, 0, c5, c0, 0);
+ MRC(ACTLR, p15, 0, c1, c0, 1);
+ MRC(EFSR, p15, 7, c15, c0, 1);
+ MRC(L2SR, p15, 3, c15, c1, 0);
+ MRC(L2CR0, p15, 3, c15, c0, 1);
+ MRC(L2CPUESR, p15, 3, c15, c1, 1);
+ MRC(L2CPUCR, p15, 3, c15, c0, 2);
+ MRC(SPESR, p15, 1, c9, c7, 0);
+ MRC(SPCR, p15, 0, c9, c7, 0);
+ MRC(DMACHSR, p15, 1, c11, c0, 0);
+ MRC(DMACHESR, p15, 1, c11, c0, 1);
+ MRC(DMACHCR, p15, 0, c11, c0, 2);
+
+ /* clear out EFSR and ADFSR after fault */
+ asm volatile ("mcr p15, 7, %0, c15, c0, 1\n\t"
+ "mcr p15, 0, %0, c5, c1, 0"
+ : : "r" (0));
+#endif
+#if defined(CONFIG_ARCH_MSM_SCORPION) && !defined(CONFIG_MSM_SMP)
+ pr_info("%s: TCSR_SPARE2 = 0x%.8x\n", __func__, readl(MSM_TCSR_SPARE2));
+#endif
+ return 1;
+}
+
static struct fsr_info {
int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
int sig;
@@ -521,7 +572,7 @@
{ do_bad, SIGBUS, 0, "unknown 19" },
{ do_bad, SIGBUS, 0, "lock abort" }, /* xscale */
{ do_bad, SIGBUS, 0, "unknown 21" },
- { do_bad, SIGBUS, BUS_OBJERR, "imprecise external abort" }, /* xscale */
+ { do_imprecise_ext, SIGBUS, BUS_OBJERR, "imprecise external abort" }, /* xscale */
{ do_bad, SIGBUS, 0, "unknown 23" },
{ do_bad, SIGBUS, 0, "dcache parity error" }, /* xscale */
{ do_bad, SIGBUS, 0, "unknown 25" },
@@ -555,6 +606,11 @@
const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
struct siginfo info;
+#ifdef CONFIG_EMULATE_DOMAIN_MANAGER_V7
+ if (emulate_domain_manager_data_abort(fsr, addr))
+ return;
+#endif
+
if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
return;
@@ -623,6 +679,11 @@
const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr);
struct siginfo info;
+#ifdef CONFIG_EMULATE_DOMAIN_MANAGER_V7
+ if (emulate_domain_manager_prefetch_abort(ifsr, addr))
+ return;
+#endif
+
if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
return;