aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-msm/msm_fault_handlers.c
blob: 7b2dc8c3c5730880fbe13ef3d53b5e7ca47ee758 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/*
 *  Copyright (C) 1995  Linus Torvalds
 *  Modifications for ARM processor (c) 1995-2004 Russell King
 *  Copyright (c) 2010, 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 as
 * published by the Free Software Foundation.
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/signal.h>
#include <linux/cpumask.h>
#include "acpuclock.h"

#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)

static int msm_imp_ext_abort(unsigned long addr, unsigned int fsr,
			     struct pt_regs *regs)
{
	int cpu;
	unsigned int regval;
	static unsigned char flush_toggle;

	asm("mrc p15, 7, %0, c15, c0, 1\n" /* read EFSR for fault status */
	    : "=r" (regval));
	if (regval == 0x2) {
		/* Fault was caused by icache parity error. Alternate
		 * simply retrying the access and flushing the icache. */
		flush_toggle ^= 1;
		if (flush_toggle)
			asm("mcr p15, 0, %0, c7, c5, 0\n"
				:
				: "r" (regval)); /* input value is ignored */
		/* Clear fault in EFSR. */
		asm("mcr p15, 7, %0, c15, c0, 1\n"
			:
			: "r" (regval));
		/* Clear fault in ADFSR. */
		regval = 0;
		asm("mcr p15, 0, %0, c5, c1, 0\n"
			:
			: "r" (regval));
		return 0;
	}

	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);
	for_each_online_cpu(cpu)
		pr_info("cpu %d, acpuclk rate: %lu kHz\n", cpu,
			acpuclk_get_rate(cpu));

	return 1;
}

static int __init msm_register_fault_handlers(void)
{
	/* hook in our handler for imprecise abort for when we get
	   i-cache parity errors */
	hook_fault_code(22, msm_imp_ext_abort, SIGBUS, 0,
			"imprecise external abort");

	return 0;
}
arch_initcall(msm_register_fault_handlers);