11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * ip22-berr.c: Bus error handling. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2002, 2003 Ladislav Michl (ladis@linux-mips.org) 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 71da177e4SLinus Torvalds #include <linux/init.h> 81da177e4SLinus Torvalds #include <linux/kernel.h> 91da177e4SLinus Torvalds #include <linux/sched.h> 101da177e4SLinus Torvalds 111da177e4SLinus Torvalds #include <asm/addrspace.h> 121da177e4SLinus Torvalds #include <asm/system.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 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 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 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); 1011da177e4SLinus Torvalds force_sig(SIGBUS, current); 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 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 1131da177e4SLinus Torvalds void __init ip22_be_init(void) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds board_be_handler = ip22_be_handler; 1161da177e4SLinus Torvalds } 117