aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/pasemi/setup.c
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2007-09-04 22:09:23 -0400
committerPaul Mackerras <paulus@samba.org>2007-09-13 11:33:21 -0400
commitcd7834167ffb66b470e4d9edb10efb5c1a2dfe7f (patch)
tree0933e803d11e2f0c2142e2c60b096fb7d34b8a35 /arch/powerpc/platforms/pasemi/setup.c
parent2e1957fd47b9d4b7bf35be2ec3d4b5e3eefe5cc0 (diff)
[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: Olof Johansson <olof@lixom.net> Signed-off-by: Paul Mackerras <paulus@samba.org>
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 @@
39 39
40#include "pasemi.h" 40#include "pasemi.h"
41 41
42/* SDC reset register, must be pre-mapped at reset time */
42static void __iomem *reset_reg; 43static void __iomem *reset_reg;
43 44
45/* Various error status registers, must be pre-mapped at MCE time */
46
47#define MAX_MCE_REGS 32
48struct mce_regs {
49 char *name;
50 void __iomem *addr;
51};
52
53static struct mce_regs mce_regs[MAX_MCE_REGS];
54static int num_mce_regs;
55
56
44static void pas_restart(char *cmd) 57static void pas_restart(char *cmd)
45{ 58{
46 printk("Restarting...\n"); 59 printk("Restarting...\n");
@@ -106,6 +119,59 @@ void __init pas_setup_arch(void)
106 pasemi_idle_init(); 119 pasemi_idle_init();
107} 120}
108 121
122static int __init pas_setup_mce_regs(void)
123{
124 struct pci_dev *dev;
125 int reg;
126
127 if (!machine_is(pasemi))
128 return -ENODEV;
129
130 /* Remap various SoC status registers for use by the MCE handler */
131
132 reg = 0;
133
134 dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, NULL);
135 while (dev && reg < MAX_MCE_REGS) {
136 mce_regs[reg].name = kasprintf(GFP_KERNEL,
137 "mc%d_mcdebug_errsta", reg);
138 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x730);
139 dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, dev);
140 reg++;
141 }
142
143 dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
144 if (dev && reg+4 < MAX_MCE_REGS) {
145 mce_regs[reg].name = "iobdbg_IntStatus1";
146 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x438);
147 reg++;
148 mce_regs[reg].name = "iobdbg_IOCTbusIntDbgReg";
149 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x454);
150 reg++;
151 mce_regs[reg].name = "iobiom_IntStatus";
152 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc10);
153 reg++;
154 mce_regs[reg].name = "iobiom_IntDbgReg";
155 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc1c);
156 reg++;
157 }
158
159 dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa009, NULL);
160 if (dev && reg+2 < MAX_MCE_REGS) {
161 mce_regs[reg].name = "l2csts_IntStatus";
162 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x200);
163 reg++;
164 mce_regs[reg].name = "l2csts_Cnt";
165 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x214);
166 reg++;
167 }
168
169 num_mce_regs = reg;
170
171 return 0;
172}
173device_initcall(pas_setup_mce_regs);
174
109static __init void pas_init_IRQ(void) 175static __init void pas_init_IRQ(void)
110{ 176{
111 struct device_node *np; 177 struct device_node *np;
@@ -166,25 +232,34 @@ static int pas_machine_check_handler(struct pt_regs *regs)
166{ 232{
167 int cpu = smp_processor_id(); 233 int cpu = smp_processor_id();
168 unsigned long srr0, srr1, dsisr; 234 unsigned long srr0, srr1, dsisr;
235 int dump_slb = 0;
236 int i;
169 237
170 srr0 = regs->nip; 238 srr0 = regs->nip;
171 srr1 = regs->msr; 239 srr1 = regs->msr;
172 dsisr = mfspr(SPRN_DSISR); 240 dsisr = mfspr(SPRN_DSISR);
173 printk(KERN_ERR "Machine Check on CPU %d\n", cpu); 241 printk(KERN_ERR "Machine Check on CPU %d\n", cpu);
174 printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); 242 printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1);
175 printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar); 243 printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar);
244 printk(KERN_ERR "BER 0x%016lx MER 0x%016lx\n", mfspr(SPRN_PA6T_BER),
245 mfspr(SPRN_PA6T_MER));
246 printk(KERN_ERR "IER 0x%016lx DER 0x%016lx\n", mfspr(SPRN_PA6T_IER),
247 mfspr(SPRN_PA6T_DER));
176 printk(KERN_ERR "Cause:\n"); 248 printk(KERN_ERR "Cause:\n");
177 249
178 if (srr1 & 0x200000) 250 if (srr1 & 0x200000)
179 printk(KERN_ERR "Signalled by SDC\n"); 251 printk(KERN_ERR "Signalled by SDC\n");
252
180 if (srr1 & 0x100000) { 253 if (srr1 & 0x100000) {
181 printk(KERN_ERR "Load/Store detected error:\n"); 254 printk(KERN_ERR "Load/Store detected error:\n");
182 if (dsisr & 0x8000) 255 if (dsisr & 0x8000)
183 printk(KERN_ERR "D-cache ECC double-bit error or bus error\n"); 256 printk(KERN_ERR "D-cache ECC double-bit error or bus error\n");
184 if (dsisr & 0x4000) 257 if (dsisr & 0x4000)
185 printk(KERN_ERR "LSU snoop response error\n"); 258 printk(KERN_ERR "LSU snoop response error\n");
186 if (dsisr & 0x2000) 259 if (dsisr & 0x2000) {
187 printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n"); 260 printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n");
261 dump_slb = 1;
262 }
188 if (dsisr & 0x1000) 263 if (dsisr & 0x1000)
189 printk(KERN_ERR "Recoverable Duptags\n"); 264 printk(KERN_ERR "Recoverable Duptags\n");
190 if (dsisr & 0x800) 265 if (dsisr & 0x800)
@@ -192,13 +267,40 @@ static int pas_machine_check_handler(struct pt_regs *regs)
192 if (dsisr & 0x400) 267 if (dsisr & 0x400)
193 printk(KERN_ERR "TLB parity error count overflow\n"); 268 printk(KERN_ERR "TLB parity error count overflow\n");
194 } 269 }
270
195 if (srr1 & 0x80000) 271 if (srr1 & 0x80000)
196 printk(KERN_ERR "Bus Error\n"); 272 printk(KERN_ERR "Bus Error\n");
197 if (srr1 & 0x40000) 273
274 if (srr1 & 0x40000) {
198 printk(KERN_ERR "I-side SLB multiple hit\n"); 275 printk(KERN_ERR "I-side SLB multiple hit\n");
276 dump_slb = 1;
277 }
278
199 if (srr1 & 0x20000) 279 if (srr1 & 0x20000)
200 printk(KERN_ERR "I-cache parity error hit\n"); 280 printk(KERN_ERR "I-cache parity error hit\n");
201 281
282 if (num_mce_regs == 0)
283 printk(KERN_ERR "No MCE registers mapped yet, can't dump\n");
284 else
285 printk(KERN_ERR "SoC debug registers:\n");
286
287 for (i = 0; i < num_mce_regs; i++)
288 printk(KERN_ERR "%s: 0x%08x\n", mce_regs[i].name,
289 in_le32(mce_regs[i].addr));
290
291 if (dump_slb) {
292 unsigned long e, v;
293 int i;
294
295 printk(KERN_ERR "slb contents:\n");
296 for (i = 0; i < SLB_NUM_ENTRIES; i++) {
297 asm volatile("slbmfee %0,%1" : "=r" (e) : "r" (i));
298 asm volatile("slbmfev %0,%1" : "=r" (v) : "r" (i));
299 printk(KERN_ERR "%02d %016lx %016lx\n", i, e, v);
300 }
301 }
302
303
202 /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ 304 /* SRR1[62] is from MSR[62] if recoverable, so pass that back */
203 return !!(srr1 & 0x2); 305 return !!(srr1 & 0x2);
204} 306}