PageRenderTime 46ms CodeModel.GetById 17ms app.highlight 23ms RepoModel.GetById 0ms app.codeStats 0ms

/arch/mips/sgi-ip22/ip28-berr.c

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