xref: /openbmc/linux/arch/mips/sgi-ip22/ip22-berr.c (revision 1f761b3e)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * ip22-berr.c: Bus error handling.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 2002, 2003 Ladislav Michl (ladis@linux-mips.org)
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds #include <linux/init.h>
91da177e4SLinus Torvalds #include <linux/kernel.h>
103f07c014SIngo Molnar #include <linux/sched/signal.h>
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <asm/addrspace.h>
131da177e4SLinus Torvalds #include <asm/traps.h>
141da177e4SLinus Torvalds #include <asm/branch.h>
15937a8015SRalf Baechle #include <asm/irq_regs.h>
161da177e4SLinus Torvalds #include <asm/sgi/mc.h>
171da177e4SLinus Torvalds #include <asm/sgi/hpc3.h>
181da177e4SLinus Torvalds #include <asm/sgi/ioc.h>
191da177e4SLinus Torvalds #include <asm/sgi/ip22.h>
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds static unsigned int cpu_err_stat;	/* Status reg for CPU */
231da177e4SLinus Torvalds static unsigned int gio_err_stat;	/* Status reg for GIO */
241da177e4SLinus Torvalds static unsigned int cpu_err_addr;	/* Error address reg for CPU */
251da177e4SLinus Torvalds static unsigned int gio_err_addr;	/* Error address reg for GIO */
261da177e4SLinus Torvalds static unsigned int extio_stat;
271da177e4SLinus Torvalds static unsigned int hpc3_berr_stat;	/* Bus error interrupt status */
281da177e4SLinus Torvalds 
save_and_clear_buserr(void)291da177e4SLinus Torvalds static void save_and_clear_buserr(void)
301da177e4SLinus Torvalds {
311da177e4SLinus Torvalds 	/* save status registers */
321da177e4SLinus Torvalds 	cpu_err_addr = sgimc->cerr;
331da177e4SLinus Torvalds 	cpu_err_stat = sgimc->cstat;
341da177e4SLinus Torvalds 	gio_err_addr = sgimc->gerr;
351da177e4SLinus Torvalds 	gio_err_stat = sgimc->gstat;
361da177e4SLinus Torvalds 	extio_stat = ip22_is_fullhouse() ? sgioc->extio : (sgint->errstat << 4);
371da177e4SLinus Torvalds 	hpc3_berr_stat = hpc3c0->bestat;
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds 	sgimc->cstat = sgimc->gstat = 0;
401da177e4SLinus Torvalds }
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds #define GIO_ERRMASK	0xff00
431da177e4SLinus Torvalds #define CPU_ERRMASK	0x3f00
441da177e4SLinus Torvalds 
print_buserr(void)451da177e4SLinus Torvalds static void print_buserr(void)
461da177e4SLinus Torvalds {
471da177e4SLinus Torvalds 	if (extio_stat & EXTIO_MC_BUSERR)
481da177e4SLinus Torvalds 		printk(KERN_ERR "MC Bus Error\n");
491da177e4SLinus Torvalds 	if (extio_stat & EXTIO_HPC3_BUSERR)
501da177e4SLinus Torvalds 		printk(KERN_ERR "HPC3 Bus Error 0x%x:<id=0x%x,%s,lane=0x%x>\n",
511da177e4SLinus Torvalds 			hpc3_berr_stat,
521da177e4SLinus Torvalds 			(hpc3_berr_stat & HPC3_BESTAT_PIDMASK) >>
531da177e4SLinus Torvalds 					  HPC3_BESTAT_PIDSHIFT,
541da177e4SLinus Torvalds 			(hpc3_berr_stat & HPC3_BESTAT_CTYPE) ? "PIO" : "DMA",
551da177e4SLinus Torvalds 			hpc3_berr_stat & HPC3_BESTAT_BLMASK);
561da177e4SLinus Torvalds 	if (extio_stat & EXTIO_EISA_BUSERR)
571da177e4SLinus Torvalds 		printk(KERN_ERR "EISA Bus Error\n");
581da177e4SLinus Torvalds 	if (cpu_err_stat & CPU_ERRMASK)
591da177e4SLinus Torvalds 		printk(KERN_ERR "CPU error 0x%x<%s%s%s%s%s%s> @ 0x%08x\n",
601da177e4SLinus Torvalds 			cpu_err_stat,
611da177e4SLinus Torvalds 			cpu_err_stat & SGIMC_CSTAT_RD ? "RD " : "",
621da177e4SLinus Torvalds 			cpu_err_stat & SGIMC_CSTAT_PAR ? "PAR " : "",
631da177e4SLinus Torvalds 			cpu_err_stat & SGIMC_CSTAT_ADDR ? "ADDR " : "",
641da177e4SLinus Torvalds 			cpu_err_stat & SGIMC_CSTAT_SYSAD_PAR ? "SYSAD " : "",
651da177e4SLinus Torvalds 			cpu_err_stat & SGIMC_CSTAT_SYSCMD_PAR ? "SYSCMD " : "",
661da177e4SLinus Torvalds 			cpu_err_stat & SGIMC_CSTAT_BAD_DATA ? "BAD_DATA " : "",
671da177e4SLinus Torvalds 			cpu_err_addr);
681da177e4SLinus Torvalds 	if (gio_err_stat & GIO_ERRMASK)
691da177e4SLinus Torvalds 		printk(KERN_ERR "GIO error 0x%x:<%s%s%s%s%s%s%s%s> @ 0x%08x\n",
701da177e4SLinus Torvalds 			gio_err_stat,
711da177e4SLinus Torvalds 			gio_err_stat & SGIMC_GSTAT_RD ? "RD " : "",
721da177e4SLinus Torvalds 			gio_err_stat & SGIMC_GSTAT_WR ? "WR " : "",
731da177e4SLinus Torvalds 			gio_err_stat & SGIMC_GSTAT_TIME ? "TIME " : "",
741da177e4SLinus Torvalds 			gio_err_stat & SGIMC_GSTAT_PROM ? "PROM " : "",
751da177e4SLinus Torvalds 			gio_err_stat & SGIMC_GSTAT_ADDR ? "ADDR " : "",
761da177e4SLinus Torvalds 			gio_err_stat & SGIMC_GSTAT_BC ? "BC " : "",
771da177e4SLinus Torvalds 			gio_err_stat & SGIMC_GSTAT_PIO_RD ? "PIO_RD " : "",
781da177e4SLinus Torvalds 			gio_err_stat & SGIMC_GSTAT_PIO_WR ? "PIO_WR " : "",
791da177e4SLinus Torvalds 			gio_err_addr);
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds /*
831da177e4SLinus Torvalds  * MC sends an interrupt whenever bus or parity errors occur. In addition,
841da177e4SLinus Torvalds  * if the error happened during a CPU read, it also asserts the bus error
851da177e4SLinus Torvalds  * pin on the R4K. Code in bus error handler save the MC bus error registers
861da177e4SLinus Torvalds  * and then clear the interrupt when this happens.
871da177e4SLinus Torvalds  */
881da177e4SLinus Torvalds 
ip22_be_interrupt(int irq)89937a8015SRalf Baechle void ip22_be_interrupt(int irq)
901da177e4SLinus Torvalds {
911da177e4SLinus Torvalds 	const int field = 2 * sizeof(unsigned long);
92ce384d83SYury Polyanskiy 	struct pt_regs *regs = get_irq_regs();
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds 	save_and_clear_buserr();
951da177e4SLinus Torvalds 	print_buserr();
961da177e4SLinus Torvalds 	printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n",
971da177e4SLinus Torvalds 	       (regs->cp0_cause & 4) ? "Data" : "Instruction",
981da177e4SLinus Torvalds 	       field, regs->cp0_epc, field, regs->regs[31]);
991da177e4SLinus Torvalds 	/* Assume it would be too dangerous to continue ... */
1001da177e4SLinus Torvalds 	die_if_kernel("Oops", regs);
1013cf5d076SEric W. Biederman 	force_sig(SIGBUS);
1021da177e4SLinus Torvalds }
1031da177e4SLinus Torvalds 
ip22_be_handler(struct pt_regs * regs,int is_fixup)1041da177e4SLinus Torvalds static int ip22_be_handler(struct pt_regs *regs, int is_fixup)
1051da177e4SLinus Torvalds {
1061da177e4SLinus Torvalds 	save_and_clear_buserr();
1071da177e4SLinus Torvalds 	if (is_fixup)
1081da177e4SLinus Torvalds 		return MIPS_BE_FIXUP;
1091da177e4SLinus Torvalds 	print_buserr();
1101da177e4SLinus Torvalds 	return MIPS_BE_FATAL;
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds 
ip22_be_init(void)1131da177e4SLinus Torvalds void __init ip22_be_init(void)
1141da177e4SLinus Torvalds {
115*1f761b3eSFlorian Fainelli 	mips_set_be_handler(ip22_be_handler);
1161da177e4SLinus Torvalds }
117