Commit cd783416 authored by Olof Johansson's avatar Olof Johansson Committed by Paul Mackerras

[POWERPC] pasemi: Print more information at machine check

Add printout of some SoC error status registers, and dump the SLB contents
for those machine check events where it makes sense.

Since we can't go about and ioremap registers at machine check time,
and we generally want to do as little as possible to print out the
information, pre-build a table of the registers to dump and their address
in the common PCI config space range.
Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 2e1957fd
......@@ -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);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment