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