diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/sgi-ip22/ip28-berr.c | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/sgi-ip22/ip28-berr.c')
-rw-r--r-- | arch/mips/sgi-ip22/ip28-berr.c | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/arch/mips/sgi-ip22/ip28-berr.c b/arch/mips/sgi-ip22/ip28-berr.c new file mode 100644 index 000000000..c61362d9e --- /dev/null +++ b/arch/mips/sgi-ip22/ip28-berr.c | |||
@@ -0,0 +1,488 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * ip28-berr.c: Bus error handling. | ||
4 | * | ||
5 | * Copyright (C) 2002, 2003 Ladislav Michl (ladis@linux-mips.org) | ||
6 | * Copyright (C) 2005 Peter Fuerst (pf@net.alphadv.de) - IP28 | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/mm.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/sched/debug.h> | ||
14 | #include <linux/sched/signal.h> | ||
15 | #include <linux/seq_file.h> | ||
16 | |||
17 | #include <asm/addrspace.h> | ||
18 | #include <asm/traps.h> | ||
19 | #include <asm/branch.h> | ||
20 | #include <asm/irq_regs.h> | ||
21 | #include <asm/sgi/mc.h> | ||
22 | #include <asm/sgi/hpc3.h> | ||
23 | #include <asm/sgi/ioc.h> | ||
24 | #include <asm/sgi/ip22.h> | ||
25 | #include <asm/r4kcache.h> | ||
26 | #include <linux/uaccess.h> | ||
27 | #include <asm/bootinfo.h> | ||
28 | |||
29 | static unsigned int count_be_is_fixup; | ||
30 | static unsigned int count_be_handler; | ||
31 | static unsigned int count_be_interrupt; | ||
32 | static int debug_be_interrupt; | ||
33 | |||
34 | static unsigned int cpu_err_stat; /* Status reg for CPU */ | ||
35 | static unsigned int gio_err_stat; /* Status reg for GIO */ | ||
36 | static unsigned int cpu_err_addr; /* Error address reg for CPU */ | ||
37 | static unsigned int gio_err_addr; /* Error address reg for GIO */ | ||
38 | static unsigned int extio_stat; | ||
39 | static unsigned int hpc3_berr_stat; /* Bus error interrupt status */ | ||
40 | |||
41 | struct hpc3_stat { | ||
42 | unsigned long addr; | ||
43 | unsigned int ctrl; | ||
44 | unsigned int cbp; | ||
45 | unsigned int ndptr; | ||
46 | }; | ||
47 | |||
48 | static struct { | ||
49 | struct hpc3_stat pbdma[8]; | ||
50 | struct hpc3_stat scsi[2]; | ||
51 | struct hpc3_stat ethrx, ethtx; | ||
52 | } hpc3; | ||
53 | |||
54 | static struct { | ||
55 | unsigned long err_addr; | ||
56 | struct { | ||
57 | u32 lo; | ||
58 | u32 hi; | ||
59 | } tags[1][2], tagd[4][2], tagi[4][2]; /* Way 0/1 */ | ||
60 | } cache_tags; | ||
61 | |||
62 | static inline void save_cache_tags(unsigned busaddr) | ||
63 | { | ||
64 | unsigned long addr = CAC_BASE | busaddr; | ||
65 | int i; | ||
66 | cache_tags.err_addr = addr; | ||
67 | |||
68 | /* | ||
69 | * Starting with a bus-address, save secondary cache (indexed by | ||
70 | * PA[23..18:7..6]) tags first. | ||
71 | */ | ||
72 | addr &= ~1L; | ||
73 | #define tag cache_tags.tags[0] | ||
74 | cache_op(Index_Load_Tag_S, addr); | ||
75 | tag[0].lo = read_c0_taglo(); /* PA[35:18], VA[13:12] */ | ||
76 | tag[0].hi = read_c0_taghi(); /* PA[39:36] */ | ||
77 | cache_op(Index_Load_Tag_S, addr | 1L); | ||
78 | tag[1].lo = read_c0_taglo(); /* PA[35:18], VA[13:12] */ | ||
79 | tag[1].hi = read_c0_taghi(); /* PA[39:36] */ | ||
80 | #undef tag | ||
81 | |||
82 | /* | ||
83 | * Save all primary data cache (indexed by VA[13:5]) tags which | ||
84 | * might fit to this bus-address, knowing that VA[11:0] == PA[11:0]. | ||
85 | * Saving all tags and evaluating them later is easier and safer | ||
86 | * than relying on VA[13:12] from the secondary cache tags to pick | ||
87 | * matching primary tags here already. | ||
88 | */ | ||
89 | addr &= (0xffL << 56) | ((1 << 12) - 1); | ||
90 | #define tag cache_tags.tagd[i] | ||
91 | for (i = 0; i < 4; ++i, addr += (1 << 12)) { | ||
92 | cache_op(Index_Load_Tag_D, addr); | ||
93 | tag[0].lo = read_c0_taglo(); /* PA[35:12] */ | ||
94 | tag[0].hi = read_c0_taghi(); /* PA[39:36] */ | ||
95 | cache_op(Index_Load_Tag_D, addr | 1L); | ||
96 | tag[1].lo = read_c0_taglo(); /* PA[35:12] */ | ||
97 | tag[1].hi = read_c0_taghi(); /* PA[39:36] */ | ||
98 | } | ||
99 | #undef tag | ||
100 | |||
101 | /* | ||
102 | * Save primary instruction cache (indexed by VA[13:6]) tags | ||
103 | * the same way. | ||
104 | */ | ||
105 | addr &= (0xffL << 56) | ((1 << 12) - 1); | ||
106 | #define tag cache_tags.tagi[i] | ||
107 | for (i = 0; i < 4; ++i, addr += (1 << 12)) { | ||
108 | cache_op(Index_Load_Tag_I, addr); | ||
109 | tag[0].lo = read_c0_taglo(); /* PA[35:12] */ | ||
110 | tag[0].hi = read_c0_taghi(); /* PA[39:36] */ | ||
111 | cache_op(Index_Load_Tag_I, addr | 1L); | ||
112 | tag[1].lo = read_c0_taglo(); /* PA[35:12] */ | ||
113 | tag[1].hi = read_c0_taghi(); /* PA[39:36] */ | ||
114 | } | ||
115 | #undef tag | ||
116 | } | ||
117 | |||
118 | #define GIO_ERRMASK 0xff00 | ||
119 | #define CPU_ERRMASK 0x3f00 | ||
120 | |||
121 | static void save_and_clear_buserr(void) | ||
122 | { | ||
123 | int i; | ||
124 | |||
125 | /* save status registers */ | ||
126 | cpu_err_addr = sgimc->cerr; | ||
127 | cpu_err_stat = sgimc->cstat; | ||
128 | gio_err_addr = sgimc->gerr; | ||
129 | gio_err_stat = sgimc->gstat; | ||
130 | extio_stat = sgioc->extio; | ||
131 | hpc3_berr_stat = hpc3c0->bestat; | ||
132 | |||
133 | hpc3.scsi[0].addr = (unsigned long)&hpc3c0->scsi_chan0; | ||
134 | hpc3.scsi[0].ctrl = hpc3c0->scsi_chan0.ctrl; /* HPC3_SCTRL_ACTIVE ? */ | ||
135 | hpc3.scsi[0].cbp = hpc3c0->scsi_chan0.cbptr; | ||
136 | hpc3.scsi[0].ndptr = hpc3c0->scsi_chan0.ndptr; | ||
137 | |||
138 | hpc3.scsi[1].addr = (unsigned long)&hpc3c0->scsi_chan1; | ||
139 | hpc3.scsi[1].ctrl = hpc3c0->scsi_chan1.ctrl; /* HPC3_SCTRL_ACTIVE ? */ | ||
140 | hpc3.scsi[1].cbp = hpc3c0->scsi_chan1.cbptr; | ||
141 | hpc3.scsi[1].ndptr = hpc3c0->scsi_chan1.ndptr; | ||
142 | |||
143 | hpc3.ethrx.addr = (unsigned long)&hpc3c0->ethregs.rx_cbptr; | ||
144 | hpc3.ethrx.ctrl = hpc3c0->ethregs.rx_ctrl; /* HPC3_ERXCTRL_ACTIVE ? */ | ||
145 | hpc3.ethrx.cbp = hpc3c0->ethregs.rx_cbptr; | ||
146 | hpc3.ethrx.ndptr = hpc3c0->ethregs.rx_ndptr; | ||
147 | |||
148 | hpc3.ethtx.addr = (unsigned long)&hpc3c0->ethregs.tx_cbptr; | ||
149 | hpc3.ethtx.ctrl = hpc3c0->ethregs.tx_ctrl; /* HPC3_ETXCTRL_ACTIVE ? */ | ||
150 | hpc3.ethtx.cbp = hpc3c0->ethregs.tx_cbptr; | ||
151 | hpc3.ethtx.ndptr = hpc3c0->ethregs.tx_ndptr; | ||
152 | |||
153 | for (i = 0; i < 8; ++i) { | ||
154 | /* HPC3_PDMACTRL_ISACT ? */ | ||
155 | hpc3.pbdma[i].addr = (unsigned long)&hpc3c0->pbdma[i]; | ||
156 | hpc3.pbdma[i].ctrl = hpc3c0->pbdma[i].pbdma_ctrl; | ||
157 | hpc3.pbdma[i].cbp = hpc3c0->pbdma[i].pbdma_bptr; | ||
158 | hpc3.pbdma[i].ndptr = hpc3c0->pbdma[i].pbdma_dptr; | ||
159 | } | ||
160 | i = 0; | ||
161 | if (gio_err_stat & CPU_ERRMASK) | ||
162 | i = gio_err_addr; | ||
163 | if (cpu_err_stat & CPU_ERRMASK) | ||
164 | i = cpu_err_addr; | ||
165 | save_cache_tags(i); | ||
166 | |||
167 | sgimc->cstat = sgimc->gstat = 0; | ||
168 | } | ||
169 | |||
170 | static void print_cache_tags(void) | ||
171 | { | ||
172 | u32 scb, scw; | ||
173 | int i; | ||
174 | |||
175 | printk(KERN_ERR "Cache tags @ %08x:\n", (unsigned)cache_tags.err_addr); | ||
176 | |||
177 | /* PA[31:12] shifted to PTag0 (PA[35:12]) format */ | ||
178 | scw = (cache_tags.err_addr >> 4) & 0x0fffff00; | ||
179 | |||
180 | scb = cache_tags.err_addr & ((1 << 12) - 1) & ~((1 << 5) - 1); | ||
181 | for (i = 0; i < 4; ++i) { /* for each possible VA[13:12] value */ | ||
182 | if ((cache_tags.tagd[i][0].lo & 0x0fffff00) != scw && | ||
183 | (cache_tags.tagd[i][1].lo & 0x0fffff00) != scw) | ||
184 | continue; | ||
185 | printk(KERN_ERR | ||
186 | "D: 0: %08x %08x, 1: %08x %08x (VA[13:5] %04x)\n", | ||
187 | cache_tags.tagd[i][0].hi, cache_tags.tagd[i][0].lo, | ||
188 | cache_tags.tagd[i][1].hi, cache_tags.tagd[i][1].lo, | ||
189 | scb | (1 << 12)*i); | ||
190 | } | ||
191 | scb = cache_tags.err_addr & ((1 << 12) - 1) & ~((1 << 6) - 1); | ||
192 | for (i = 0; i < 4; ++i) { /* for each possible VA[13:12] value */ | ||
193 | if ((cache_tags.tagi[i][0].lo & 0x0fffff00) != scw && | ||
194 | (cache_tags.tagi[i][1].lo & 0x0fffff00) != scw) | ||
195 | continue; | ||
196 | printk(KERN_ERR | ||
197 | "I: 0: %08x %08x, 1: %08x %08x (VA[13:6] %04x)\n", | ||
198 | cache_tags.tagi[i][0].hi, cache_tags.tagi[i][0].lo, | ||
199 | cache_tags.tagi[i][1].hi, cache_tags.tagi[i][1].lo, | ||
200 | scb | (1 << 12)*i); | ||
201 | } | ||
202 | i = read_c0_config(); | ||
203 | scb = i & (1 << 13) ? 7:6; /* scblksize = 2^[7..6] */ | ||
204 | scw = ((i >> 16) & 7) + 19 - 1; /* scwaysize = 2^[24..19] / 2 */ | ||
205 | |||
206 | i = ((1 << scw) - 1) & ~((1 << scb) - 1); | ||
207 | printk(KERN_ERR "S: 0: %08x %08x, 1: %08x %08x (PA[%u:%u] %05x)\n", | ||
208 | cache_tags.tags[0][0].hi, cache_tags.tags[0][0].lo, | ||
209 | cache_tags.tags[0][1].hi, cache_tags.tags[0][1].lo, | ||
210 | scw-1, scb, i & (unsigned)cache_tags.err_addr); | ||
211 | } | ||
212 | |||
213 | static inline const char *cause_excode_text(int cause) | ||
214 | { | ||
215 | static const char *txt[32] = | ||
216 | { "Interrupt", | ||
217 | "TLB modification", | ||
218 | "TLB (load or instruction fetch)", | ||
219 | "TLB (store)", | ||
220 | "Address error (load or instruction fetch)", | ||
221 | "Address error (store)", | ||
222 | "Bus error (instruction fetch)", | ||
223 | "Bus error (data: load or store)", | ||
224 | "Syscall", | ||
225 | "Breakpoint", | ||
226 | "Reserved instruction", | ||
227 | "Coprocessor unusable", | ||
228 | "Arithmetic Overflow", | ||
229 | "Trap", | ||
230 | "14", | ||
231 | "Floating-Point", | ||
232 | "16", "17", "18", "19", "20", "21", "22", | ||
233 | "Watch Hi/Lo", | ||
234 | "24", "25", "26", "27", "28", "29", "30", "31", | ||
235 | }; | ||
236 | return txt[(cause & 0x7c) >> 2]; | ||
237 | } | ||
238 | |||
239 | static void print_buserr(const struct pt_regs *regs) | ||
240 | { | ||
241 | const int field = 2 * sizeof(unsigned long); | ||
242 | int error = 0; | ||
243 | |||
244 | if (extio_stat & EXTIO_MC_BUSERR) { | ||
245 | printk(KERN_ERR "MC Bus Error\n"); | ||
246 | error |= 1; | ||
247 | } | ||
248 | if (extio_stat & EXTIO_HPC3_BUSERR) { | ||
249 | printk(KERN_ERR "HPC3 Bus Error 0x%x:<id=0x%x,%s,lane=0x%x>\n", | ||
250 | hpc3_berr_stat, | ||
251 | (hpc3_berr_stat & HPC3_BESTAT_PIDMASK) >> | ||
252 | HPC3_BESTAT_PIDSHIFT, | ||
253 | (hpc3_berr_stat & HPC3_BESTAT_CTYPE) ? "PIO" : "DMA", | ||
254 | hpc3_berr_stat & HPC3_BESTAT_BLMASK); | ||
255 | error |= 2; | ||
256 | } | ||
257 | if (extio_stat & EXTIO_EISA_BUSERR) { | ||
258 | printk(KERN_ERR "EISA Bus Error\n"); | ||
259 | error |= 4; | ||
260 | } | ||
261 | if (cpu_err_stat & CPU_ERRMASK) { | ||
262 | printk(KERN_ERR "CPU error 0x%x<%s%s%s%s%s%s> @ 0x%08x\n", | ||
263 | cpu_err_stat, | ||
264 | cpu_err_stat & SGIMC_CSTAT_RD ? "RD " : "", | ||
265 | cpu_err_stat & SGIMC_CSTAT_PAR ? "PAR " : "", | ||
266 | cpu_err_stat & SGIMC_CSTAT_ADDR ? "ADDR " : "", | ||
267 | cpu_err_stat & SGIMC_CSTAT_SYSAD_PAR ? "SYSAD " : "", | ||
268 | cpu_err_stat & SGIMC_CSTAT_SYSCMD_PAR ? "SYSCMD " : "", | ||
269 | cpu_err_stat & SGIMC_CSTAT_BAD_DATA ? "BAD_DATA " : "", | ||
270 | cpu_err_addr); | ||
271 | error |= 8; | ||
272 | } | ||
273 | if (gio_err_stat & GIO_ERRMASK) { | ||
274 | printk(KERN_ERR "GIO error 0x%x:<%s%s%s%s%s%s%s%s> @ 0x%08x\n", | ||
275 | gio_err_stat, | ||
276 | gio_err_stat & SGIMC_GSTAT_RD ? "RD " : "", | ||
277 | gio_err_stat & SGIMC_GSTAT_WR ? "WR " : "", | ||
278 | gio_err_stat & SGIMC_GSTAT_TIME ? "TIME " : "", | ||
279 | gio_err_stat & SGIMC_GSTAT_PROM ? "PROM " : "", | ||
280 | gio_err_stat & SGIMC_GSTAT_ADDR ? "ADDR " : "", | ||
281 | gio_err_stat & SGIMC_GSTAT_BC ? "BC " : "", | ||
282 | gio_err_stat & SGIMC_GSTAT_PIO_RD ? "PIO_RD " : "", | ||
283 | gio_err_stat & SGIMC_GSTAT_PIO_WR ? "PIO_WR " : "", | ||
284 | gio_err_addr); | ||
285 | error |= 16; | ||
286 | } | ||
287 | if (!error) | ||
288 | printk(KERN_ERR "MC: Hmm, didn't find any error condition.\n"); | ||
289 | else { | ||
290 | printk(KERN_ERR "CP0: config %08x, " | ||
291 | "MC: cpuctrl0/1: %08x/%05x, giopar: %04x\n" | ||
292 | "MC: cpu/gio_memacc: %08x/%05x, memcfg0/1: %08x/%08x\n", | ||
293 | read_c0_config(), | ||
294 | sgimc->cpuctrl0, sgimc->cpuctrl0, sgimc->giopar, | ||
295 | sgimc->cmacc, sgimc->gmacc, | ||
296 | sgimc->mconfig0, sgimc->mconfig1); | ||
297 | print_cache_tags(); | ||
298 | } | ||
299 | printk(KERN_ALERT "%s, epc == %0*lx, ra == %0*lx\n", | ||
300 | cause_excode_text(regs->cp0_cause), | ||
301 | field, regs->cp0_epc, field, regs->regs[31]); | ||
302 | } | ||
303 | |||
304 | static int check_microtlb(u32 hi, u32 lo, unsigned long vaddr) | ||
305 | { | ||
306 | /* This is likely rather similar to correct code ;-) */ | ||
307 | |||
308 | vaddr &= 0x7fffffff; /* Doc. states that top bit is ignored */ | ||
309 | |||
310 | /* If tlb-entry is valid and VPN-high (bits [30:21] ?) matches... */ | ||
311 | if ((lo & 2) && (vaddr >> 21) == ((hi<<1) >> 22)) { | ||
312 | u32 ctl = sgimc->dma_ctrl; | ||
313 | if (ctl & 1) { | ||
314 | unsigned int pgsz = (ctl & 2) ? 14:12; /* 16k:4k */ | ||
315 | /* PTEIndex is VPN-low (bits [22:14]/[20:12] ?) */ | ||
316 | unsigned long pte = (lo >> 6) << 12; /* PTEBase */ | ||
317 | pte += 8*((vaddr >> pgsz) & 0x1ff); | ||
318 | if (page_is_ram(PFN_DOWN(pte))) { | ||
319 | /* | ||
320 | * Note: Since DMA hardware does look up | ||
321 | * translation on its own, this PTE *must* | ||
322 | * match the TLB/EntryLo-register format ! | ||
323 | */ | ||
324 | unsigned long a = *(unsigned long *) | ||
325 | PHYS_TO_XKSEG_UNCACHED(pte); | ||
326 | a = (a & 0x3f) << 6; /* PFN */ | ||
327 | a += vaddr & ((1 << pgsz) - 1); | ||
328 | return cpu_err_addr == a; | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | static int check_vdma_memaddr(void) | ||
336 | { | ||
337 | if (cpu_err_stat & CPU_ERRMASK) { | ||
338 | u32 a = sgimc->maddronly; | ||
339 | |||
340 | if (!(sgimc->dma_ctrl & 0x100)) /* Xlate-bit clear ? */ | ||
341 | return cpu_err_addr == a; | ||
342 | |||
343 | if (check_microtlb(sgimc->dtlb_hi0, sgimc->dtlb_lo0, a) || | ||
344 | check_microtlb(sgimc->dtlb_hi1, sgimc->dtlb_lo1, a) || | ||
345 | check_microtlb(sgimc->dtlb_hi2, sgimc->dtlb_lo2, a) || | ||
346 | check_microtlb(sgimc->dtlb_hi3, sgimc->dtlb_lo3, a)) | ||
347 | return 1; | ||
348 | } | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static int check_vdma_gioaddr(void) | ||
353 | { | ||
354 | if (gio_err_stat & GIO_ERRMASK) { | ||
355 | u32 a = sgimc->gio_dma_trans; | ||
356 | a = (sgimc->gmaddronly & ~a) | (sgimc->gio_dma_sbits & a); | ||
357 | return gio_err_addr == a; | ||
358 | } | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | /* | ||
363 | * MC sends an interrupt whenever bus or parity errors occur. In addition, | ||
364 | * if the error happened during a CPU read, it also asserts the bus error | ||
365 | * pin on the R4K. Code in bus error handler save the MC bus error registers | ||
366 | * and then clear the interrupt when this happens. | ||
367 | */ | ||
368 | |||
369 | static int ip28_be_interrupt(const struct pt_regs *regs) | ||
370 | { | ||
371 | int i; | ||
372 | |||
373 | save_and_clear_buserr(); | ||
374 | /* | ||
375 | * Try to find out, whether we got here by a mispredicted speculative | ||
376 | * load/store operation. If so, it's not fatal, we can go on. | ||
377 | */ | ||
378 | /* Any cause other than "Interrupt" (ExcCode 0) is fatal. */ | ||
379 | if (regs->cp0_cause & CAUSEF_EXCCODE) | ||
380 | goto mips_be_fatal; | ||
381 | |||
382 | /* Any cause other than "Bus error interrupt" (IP6) is weird. */ | ||
383 | if ((regs->cp0_cause & CAUSEF_IP6) != CAUSEF_IP6) | ||
384 | goto mips_be_fatal; | ||
385 | |||
386 | if (extio_stat & (EXTIO_HPC3_BUSERR | EXTIO_EISA_BUSERR)) | ||
387 | goto mips_be_fatal; | ||
388 | |||
389 | /* Any state other than "Memory bus error" is fatal. */ | ||
390 | if (cpu_err_stat & CPU_ERRMASK & ~SGIMC_CSTAT_ADDR) | ||
391 | goto mips_be_fatal; | ||
392 | |||
393 | /* GIO errors other than timeouts are fatal */ | ||
394 | if (gio_err_stat & GIO_ERRMASK & ~SGIMC_GSTAT_TIME) | ||
395 | goto mips_be_fatal; | ||
396 | |||
397 | /* | ||
398 | * Now we have an asynchronous bus error, speculatively or DMA caused. | ||
399 | * Need to search all DMA descriptors for the error address. | ||
400 | */ | ||
401 | for (i = 0; i < sizeof(hpc3)/sizeof(struct hpc3_stat); ++i) { | ||
402 | struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i; | ||
403 | if ((cpu_err_stat & CPU_ERRMASK) && | ||
404 | (cpu_err_addr == hp->ndptr || cpu_err_addr == hp->cbp)) | ||
405 | break; | ||
406 | if ((gio_err_stat & GIO_ERRMASK) && | ||
407 | (gio_err_addr == hp->ndptr || gio_err_addr == hp->cbp)) | ||
408 | break; | ||
409 | } | ||
410 | if (i < sizeof(hpc3)/sizeof(struct hpc3_stat)) { | ||
411 | struct hpc3_stat *hp = (struct hpc3_stat *)&hpc3 + i; | ||
412 | printk(KERN_ERR "at DMA addresses: HPC3 @ %08lx:" | ||
413 | " ctl %08x, ndp %08x, cbp %08x\n", | ||
414 | CPHYSADDR(hp->addr), hp->ctrl, hp->ndptr, hp->cbp); | ||
415 | goto mips_be_fatal; | ||
416 | } | ||
417 | /* Check MC's virtual DMA stuff. */ | ||
418 | if (check_vdma_memaddr()) { | ||
419 | printk(KERN_ERR "at GIO DMA: mem address 0x%08x.\n", | ||
420 | sgimc->maddronly); | ||
421 | goto mips_be_fatal; | ||
422 | } | ||
423 | if (check_vdma_gioaddr()) { | ||
424 | printk(KERN_ERR "at GIO DMA: gio address 0x%08x.\n", | ||
425 | sgimc->gmaddronly); | ||
426 | goto mips_be_fatal; | ||
427 | } | ||
428 | /* A speculative bus error... */ | ||
429 | if (debug_be_interrupt) { | ||
430 | print_buserr(regs); | ||
431 | printk(KERN_ERR "discarded!\n"); | ||
432 | } | ||
433 | return MIPS_BE_DISCARD; | ||
434 | |||
435 | mips_be_fatal: | ||
436 | print_buserr(regs); | ||
437 | return MIPS_BE_FATAL; | ||
438 | } | ||
439 | |||
440 | void ip22_be_interrupt(int irq) | ||
441 | { | ||
442 | struct pt_regs *regs = get_irq_regs(); | ||
443 | |||
444 | count_be_interrupt++; | ||
445 | |||
446 | if (ip28_be_interrupt(regs) != MIPS_BE_DISCARD) { | ||
447 | /* Assume it would be too dangerous to continue ... */ | ||
448 | die_if_kernel("Oops", regs); | ||
449 | force_sig(SIGBUS); | ||
450 | } else if (debug_be_interrupt) | ||
451 | show_regs(regs); | ||
452 | } | ||
453 | |||
454 | static int ip28_be_handler(struct pt_regs *regs, int is_fixup) | ||
455 | { | ||
456 | /* | ||
457 | * We arrive here only in the unusual case of do_be() invocation, | ||
458 | * i.e. by a bus error exception without a bus error interrupt. | ||
459 | */ | ||
460 | if (is_fixup) { | ||
461 | count_be_is_fixup++; | ||
462 | save_and_clear_buserr(); | ||
463 | return MIPS_BE_FIXUP; | ||
464 | } | ||
465 | count_be_handler++; | ||
466 | return ip28_be_interrupt(regs); | ||
467 | } | ||
468 | |||
469 | void __init ip22_be_init(void) | ||
470 | { | ||
471 | board_be_handler = ip28_be_handler; | ||
472 | } | ||
473 | |||
474 | int ip28_show_be_info(struct seq_file *m) | ||
475 | { | ||
476 | seq_printf(m, "IP28 be fixups\t\t: %u\n", count_be_is_fixup); | ||
477 | seq_printf(m, "IP28 be interrupts\t: %u\n", count_be_interrupt); | ||
478 | seq_printf(m, "IP28 be handler\t\t: %u\n", count_be_handler); | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int __init debug_be_setup(char *str) | ||
484 | { | ||
485 | debug_be_interrupt++; | ||
486 | return 1; | ||
487 | } | ||
488 | __setup("ip28_debug_be", debug_be_setup); | ||