diff options
Diffstat (limited to 'arch/mips/sgi-ip22/ip22-berr.c')
-rw-r--r-- | arch/mips/sgi-ip22/ip22-berr.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/arch/mips/sgi-ip22/ip22-berr.c b/arch/mips/sgi-ip22/ip22-berr.c new file mode 100644 index 000000000000..a28dc7800072 --- /dev/null +++ b/arch/mips/sgi-ip22/ip22-berr.c | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * ip22-berr.c: Bus error handling. | ||
3 | * | ||
4 | * Copyright (C) 2002, 2003 Ladislav Michl (ladis@linux-mips.org) | ||
5 | */ | ||
6 | |||
7 | #include <linux/init.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/sched.h> | ||
10 | |||
11 | #include <asm/addrspace.h> | ||
12 | #include <asm/system.h> | ||
13 | #include <asm/traps.h> | ||
14 | #include <asm/branch.h> | ||
15 | #include <asm/sgi/mc.h> | ||
16 | #include <asm/sgi/hpc3.h> | ||
17 | #include <asm/sgi/ioc.h> | ||
18 | #include <asm/sgi/ip22.h> | ||
19 | |||
20 | |||
21 | static unsigned int cpu_err_stat; /* Status reg for CPU */ | ||
22 | static unsigned int gio_err_stat; /* Status reg for GIO */ | ||
23 | static unsigned int cpu_err_addr; /* Error address reg for CPU */ | ||
24 | static unsigned int gio_err_addr; /* Error address reg for GIO */ | ||
25 | static unsigned int extio_stat; | ||
26 | static unsigned int hpc3_berr_stat; /* Bus error interrupt status */ | ||
27 | |||
28 | static void save_and_clear_buserr(void) | ||
29 | { | ||
30 | /* save status registers */ | ||
31 | cpu_err_addr = sgimc->cerr; | ||
32 | cpu_err_stat = sgimc->cstat; | ||
33 | gio_err_addr = sgimc->gerr; | ||
34 | gio_err_stat = sgimc->gstat; | ||
35 | extio_stat = ip22_is_fullhouse() ? sgioc->extio : (sgint->errstat << 4); | ||
36 | hpc3_berr_stat = hpc3c0->bestat; | ||
37 | |||
38 | sgimc->cstat = sgimc->gstat = 0; | ||
39 | } | ||
40 | |||
41 | #define GIO_ERRMASK 0xff00 | ||
42 | #define CPU_ERRMASK 0x3f00 | ||
43 | |||
44 | static void print_buserr(void) | ||
45 | { | ||
46 | if (extio_stat & EXTIO_MC_BUSERR) | ||
47 | printk(KERN_ERR "MC Bus Error\n"); | ||
48 | if (extio_stat & EXTIO_HPC3_BUSERR) | ||
49 | printk(KERN_ERR "HPC3 Bus Error 0x%x:<id=0x%x,%s,lane=0x%x>\n", | ||
50 | hpc3_berr_stat, | ||
51 | (hpc3_berr_stat & HPC3_BESTAT_PIDMASK) >> | ||
52 | HPC3_BESTAT_PIDSHIFT, | ||
53 | (hpc3_berr_stat & HPC3_BESTAT_CTYPE) ? "PIO" : "DMA", | ||
54 | hpc3_berr_stat & HPC3_BESTAT_BLMASK); | ||
55 | if (extio_stat & EXTIO_EISA_BUSERR) | ||
56 | printk(KERN_ERR "EISA Bus Error\n"); | ||
57 | if (cpu_err_stat & CPU_ERRMASK) | ||
58 | printk(KERN_ERR "CPU error 0x%x<%s%s%s%s%s%s> @ 0x%08x\n", | ||
59 | cpu_err_stat, | ||
60 | cpu_err_stat & SGIMC_CSTAT_RD ? "RD " : "", | ||
61 | cpu_err_stat & SGIMC_CSTAT_PAR ? "PAR " : "", | ||
62 | cpu_err_stat & SGIMC_CSTAT_ADDR ? "ADDR " : "", | ||
63 | cpu_err_stat & SGIMC_CSTAT_SYSAD_PAR ? "SYSAD " : "", | ||
64 | cpu_err_stat & SGIMC_CSTAT_SYSCMD_PAR ? "SYSCMD " : "", | ||
65 | cpu_err_stat & SGIMC_CSTAT_BAD_DATA ? "BAD_DATA " : "", | ||
66 | cpu_err_addr); | ||
67 | if (gio_err_stat & GIO_ERRMASK) | ||
68 | printk(KERN_ERR "GIO error 0x%x:<%s%s%s%s%s%s%s%s> @ 0x%08x\n", | ||
69 | gio_err_stat, | ||
70 | gio_err_stat & SGIMC_GSTAT_RD ? "RD " : "", | ||
71 | gio_err_stat & SGIMC_GSTAT_WR ? "WR " : "", | ||
72 | gio_err_stat & SGIMC_GSTAT_TIME ? "TIME " : "", | ||
73 | gio_err_stat & SGIMC_GSTAT_PROM ? "PROM " : "", | ||
74 | gio_err_stat & SGIMC_GSTAT_ADDR ? "ADDR " : "", | ||
75 | gio_err_stat & SGIMC_GSTAT_BC ? "BC " : "", | ||
76 | gio_err_stat & SGIMC_GSTAT_PIO_RD ? "PIO_RD " : "", | ||
77 | gio_err_stat & SGIMC_GSTAT_PIO_WR ? "PIO_WR " : "", | ||
78 | gio_err_addr); | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * MC sends an interrupt whenever bus or parity errors occur. In addition, | ||
83 | * if the error happened during a CPU read, it also asserts the bus error | ||
84 | * pin on the R4K. Code in bus error handler save the MC bus error registers | ||
85 | * and then clear the interrupt when this happens. | ||
86 | */ | ||
87 | |||
88 | void ip22_be_interrupt(int irq, struct pt_regs *regs) | ||
89 | { | ||
90 | const int field = 2 * sizeof(unsigned long); | ||
91 | |||
92 | save_and_clear_buserr(); | ||
93 | print_buserr(); | ||
94 | printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n", | ||
95 | (regs->cp0_cause & 4) ? "Data" : "Instruction", | ||
96 | field, regs->cp0_epc, field, regs->regs[31]); | ||
97 | /* Assume it would be too dangerous to continue ... */ | ||
98 | die_if_kernel("Oops", regs); | ||
99 | force_sig(SIGBUS, current); | ||
100 | } | ||
101 | |||
102 | static int ip22_be_handler(struct pt_regs *regs, int is_fixup) | ||
103 | { | ||
104 | save_and_clear_buserr(); | ||
105 | if (is_fixup) | ||
106 | return MIPS_BE_FIXUP; | ||
107 | print_buserr(); | ||
108 | return MIPS_BE_FATAL; | ||
109 | } | ||
110 | |||
111 | void __init ip22_be_init(void) | ||
112 | { | ||
113 | board_be_handler = ip22_be_handler; | ||
114 | } | ||