summaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pasemi/setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/pasemi/setup.c')
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c110
1 files changed, 106 insertions, 4 deletions
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index 05def6282f8..fe9a5d63143 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -39,8 +39,21 @@
#include "pasemi.h"
+/* SDC reset register, must be pre-mapped at reset time */
static void __iomem *reset_reg;
+/* Various error status registers, must be pre-mapped at MCE time */
+
+#define MAX_MCE_REGS 32
+struct mce_regs {
+ char *name;
+ void __iomem *addr;
+};
+
+static struct mce_regs mce_regs[MAX_MCE_REGS];
+static int num_mce_regs;
+
+
static void pas_restart(char *cmd)
{
printk("Restarting...\n");
@@ -106,6 +119,59 @@ void __init pas_setup_arch(void)
pasemi_idle_init();
}
+static int __init pas_setup_mce_regs(void)
+{
+ struct pci_dev *dev;
+ int reg;
+
+ if (!machine_is(pasemi))
+ return -ENODEV;
+
+ /* Remap various SoC status registers for use by the MCE handler */
+
+ reg = 0;
+
+ dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, NULL);
+ while (dev && reg < MAX_MCE_REGS) {
+ mce_regs[reg].name = kasprintf(GFP_KERNEL,
+ "mc%d_mcdebug_errsta", reg);
+ mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x730);
+ dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, dev);
+ reg++;
+ }
+
+ dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
+ if (dev && reg+4 < MAX_MCE_REGS) {
+ mce_regs[reg].name = "iobdbg_IntStatus1";
+ mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x438);
+ reg++;
+ mce_regs[reg].name = "iobdbg_IOCTbusIntDbgReg";
+ mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x454);
+ reg++;
+ mce_regs[reg].name = "iobiom_IntStatus";
+ mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc10);
+ reg++;
+ mce_regs[reg].name = "iobiom_IntDbgReg";
+ mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc1c);
+ reg++;
+ }
+
+ dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa009, NULL);
+ if (dev && reg+2 < MAX_MCE_REGS) {
+ mce_regs[reg].name = "l2csts_IntStatus";
+ mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x200);
+ reg++;
+ mce_regs[reg].name = "l2csts_Cnt";
+ mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x214);
+ reg++;
+ }
+
+ num_mce_regs = reg;
+
+ return 0;
+}
+device_initcall(pas_setup_mce_regs);
+
static __init void pas_init_IRQ(void)
{
struct device_node *np;
@@ -166,25 +232,34 @@ static int pas_machine_check_handler(struct pt_regs *regs)
{
int cpu = smp_processor_id();
unsigned long srr0, srr1, dsisr;
+ int dump_slb = 0;
+ int i;
srr0 = regs->nip;
srr1 = regs->msr;
dsisr = mfspr(SPRN_DSISR);
printk(KERN_ERR "Machine Check on CPU %d\n", cpu);
- printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1);
- printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar);
+ printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1);
+ printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar);
+ printk(KERN_ERR "BER 0x%016lx MER 0x%016lx\n", mfspr(SPRN_PA6T_BER),
+ mfspr(SPRN_PA6T_MER));
+ printk(KERN_ERR "IER 0x%016lx DER 0x%016lx\n", mfspr(SPRN_PA6T_IER),
+ mfspr(SPRN_PA6T_DER));
printk(KERN_ERR "Cause:\n");
if (srr1 & 0x200000)
printk(KERN_ERR "Signalled by SDC\n");
+
if (srr1 & 0x100000) {
printk(KERN_ERR "Load/Store detected error:\n");
if (dsisr & 0x8000)
printk(KERN_ERR "D-cache ECC double-bit error or bus error\n");
if (dsisr & 0x4000)
printk(KERN_ERR "LSU snoop response error\n");
- if (dsisr & 0x2000)
+ if (dsisr & 0x2000) {
printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n");
+ dump_slb = 1;
+ }
if (dsisr & 0x1000)
printk(KERN_ERR "Recoverable Duptags\n");
if (dsisr & 0x800)
@@ -192,13 +267,40 @@ static int pas_machine_check_handler(struct pt_regs *regs)
if (dsisr & 0x400)
printk(KERN_ERR "TLB parity error count overflow\n");
}
+
if (srr1 & 0x80000)
printk(KERN_ERR "Bus Error\n");
- if (srr1 & 0x40000)
+
+ if (srr1 & 0x40000) {
printk(KERN_ERR "I-side SLB multiple hit\n");
+ dump_slb = 1;
+ }
+
if (srr1 & 0x20000)
printk(KERN_ERR "I-cache parity error hit\n");
+ if (num_mce_regs == 0)
+ printk(KERN_ERR "No MCE registers mapped yet, can't dump\n");
+ else
+ printk(KERN_ERR "SoC debug registers:\n");
+
+ for (i = 0; i < num_mce_regs; i++)
+ printk(KERN_ERR "%s: 0x%08x\n", mce_regs[i].name,
+ in_le32(mce_regs[i].addr));
+
+ if (dump_slb) {
+ unsigned long e, v;
+ int i;
+
+ printk(KERN_ERR "slb contents:\n");
+ for (i = 0; i < SLB_NUM_ENTRIES; i++) {
+ asm volatile("slbmfee %0,%1" : "=r" (e) : "r" (i));
+ asm volatile("slbmfev %0,%1" : "=r" (v) : "r" (i));
+ printk(KERN_ERR "%02d %016lx %016lx\n", i, e, v);
+ }
+ }
+
+
/* SRR1[62] is from MSR[62] if recoverable, so pass that back */
return !!(srr1 & 0x2);
}