aboutsummaryrefslogtreecommitdiffstats
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.c134
1 files changed, 119 insertions, 15 deletions
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index ffe6528048b5..5ddf40a66ae8 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");
@@ -50,26 +63,30 @@ static void pas_restart(char *cmd)
50 63
51#ifdef CONFIG_SMP 64#ifdef CONFIG_SMP
52static DEFINE_SPINLOCK(timebase_lock); 65static DEFINE_SPINLOCK(timebase_lock);
66static unsigned long timebase;
53 67
54static void __devinit pas_give_timebase(void) 68static void __devinit pas_give_timebase(void)
55{ 69{
56 unsigned long tb;
57
58 spin_lock(&timebase_lock); 70 spin_lock(&timebase_lock);
59 mtspr(SPRN_TBCTL, TBCTL_FREEZE); 71 mtspr(SPRN_TBCTL, TBCTL_FREEZE);
60 tb = mftb(); 72 isync();
61 mtspr(SPRN_TBCTL, TBCTL_UPDATE_LOWER | (tb & 0xffffffff)); 73 timebase = get_tb();
62 mtspr(SPRN_TBCTL, TBCTL_UPDATE_UPPER | (tb >> 32));
63 mtspr(SPRN_TBCTL, TBCTL_RESTART);
64 spin_unlock(&timebase_lock); 74 spin_unlock(&timebase_lock);
65 pr_debug("pas_give_timebase: cpu %d gave tb %lx\n", 75
66 smp_processor_id(), tb); 76 while (timebase)
77 barrier();
78 mtspr(SPRN_TBCTL, TBCTL_RESTART);
67} 79}
68 80
69static void __devinit pas_take_timebase(void) 81static void __devinit pas_take_timebase(void)
70{ 82{
71 pr_debug("pas_take_timebase: cpu %d has tb %lx\n", 83 while (!timebase)
72 smp_processor_id(), mftb()); 84 smp_rmb();
85
86 spin_lock(&timebase_lock);
87 set_tb(timebase >> 32, timebase & 0xffffffff);
88 timebase = 0;
89 spin_unlock(&timebase_lock);
73} 90}
74 91
75struct smp_ops_t pas_smp_ops = { 92struct smp_ops_t pas_smp_ops = {
@@ -98,9 +115,60 @@ void __init pas_setup_arch(void)
98 /* Remap SDC register for doing reset */ 115 /* Remap SDC register for doing reset */
99 /* XXXOJN This should maybe come out of the device tree */ 116 /* XXXOJN This should maybe come out of the device tree */
100 reset_reg = ioremap(0xfc101100, 4); 117 reset_reg = ioremap(0xfc101100, 4);
118}
119
120static int __init pas_setup_mce_regs(void)
121{
122 struct pci_dev *dev;
123 int reg;
124
125 if (!machine_is(pasemi))
126 return -ENODEV;
127
128 /* Remap various SoC status registers for use by the MCE handler */
129
130 reg = 0;
131
132 dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, NULL);
133 while (dev && reg < MAX_MCE_REGS) {
134 mce_regs[reg].name = kasprintf(GFP_KERNEL,
135 "mc%d_mcdebug_errsta", reg);
136 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x730);
137 dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, dev);
138 reg++;
139 }
140
141 dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
142 if (dev && reg+4 < MAX_MCE_REGS) {
143 mce_regs[reg].name = "iobdbg_IntStatus1";
144 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x438);
145 reg++;
146 mce_regs[reg].name = "iobdbg_IOCTbusIntDbgReg";
147 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x454);
148 reg++;
149 mce_regs[reg].name = "iobiom_IntStatus";
150 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc10);
151 reg++;
152 mce_regs[reg].name = "iobiom_IntDbgReg";
153 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc1c);
154 reg++;
155 }
156
157 dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa009, NULL);
158 if (dev && reg+2 < MAX_MCE_REGS) {
159 mce_regs[reg].name = "l2csts_IntStatus";
160 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x200);
161 reg++;
162 mce_regs[reg].name = "l2csts_Cnt";
163 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x214);
164 reg++;
165 }
101 166
102 pasemi_idle_init(); 167 num_mce_regs = reg;
168
169 return 0;
103} 170}
171device_initcall(pas_setup_mce_regs);
104 172
105static __init void pas_init_IRQ(void) 173static __init void pas_init_IRQ(void)
106{ 174{
@@ -162,25 +230,34 @@ static int pas_machine_check_handler(struct pt_regs *regs)
162{ 230{
163 int cpu = smp_processor_id(); 231 int cpu = smp_processor_id();
164 unsigned long srr0, srr1, dsisr; 232 unsigned long srr0, srr1, dsisr;
233 int dump_slb = 0;
234 int i;
165 235
166 srr0 = regs->nip; 236 srr0 = regs->nip;
167 srr1 = regs->msr; 237 srr1 = regs->msr;
168 dsisr = mfspr(SPRN_DSISR); 238 dsisr = mfspr(SPRN_DSISR);
169 printk(KERN_ERR "Machine Check on CPU %d\n", cpu); 239 printk(KERN_ERR "Machine Check on CPU %d\n", cpu);
170 printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); 240 printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1);
171 printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar); 241 printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar);
242 printk(KERN_ERR "BER 0x%016lx MER 0x%016lx\n", mfspr(SPRN_PA6T_BER),
243 mfspr(SPRN_PA6T_MER));
244 printk(KERN_ERR "IER 0x%016lx DER 0x%016lx\n", mfspr(SPRN_PA6T_IER),
245 mfspr(SPRN_PA6T_DER));
172 printk(KERN_ERR "Cause:\n"); 246 printk(KERN_ERR "Cause:\n");
173 247
174 if (srr1 & 0x200000) 248 if (srr1 & 0x200000)
175 printk(KERN_ERR "Signalled by SDC\n"); 249 printk(KERN_ERR "Signalled by SDC\n");
250
176 if (srr1 & 0x100000) { 251 if (srr1 & 0x100000) {
177 printk(KERN_ERR "Load/Store detected error:\n"); 252 printk(KERN_ERR "Load/Store detected error:\n");
178 if (dsisr & 0x8000) 253 if (dsisr & 0x8000)
179 printk(KERN_ERR "D-cache ECC double-bit error or bus error\n"); 254 printk(KERN_ERR "D-cache ECC double-bit error or bus error\n");
180 if (dsisr & 0x4000) 255 if (dsisr & 0x4000)
181 printk(KERN_ERR "LSU snoop response error\n"); 256 printk(KERN_ERR "LSU snoop response error\n");
182 if (dsisr & 0x2000) 257 if (dsisr & 0x2000) {
183 printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n"); 258 printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n");
259 dump_slb = 1;
260 }
184 if (dsisr & 0x1000) 261 if (dsisr & 0x1000)
185 printk(KERN_ERR "Recoverable Duptags\n"); 262 printk(KERN_ERR "Recoverable Duptags\n");
186 if (dsisr & 0x800) 263 if (dsisr & 0x800)
@@ -188,13 +265,40 @@ static int pas_machine_check_handler(struct pt_regs *regs)
188 if (dsisr & 0x400) 265 if (dsisr & 0x400)
189 printk(KERN_ERR "TLB parity error count overflow\n"); 266 printk(KERN_ERR "TLB parity error count overflow\n");
190 } 267 }
268
191 if (srr1 & 0x80000) 269 if (srr1 & 0x80000)
192 printk(KERN_ERR "Bus Error\n"); 270 printk(KERN_ERR "Bus Error\n");
193 if (srr1 & 0x40000) 271
272 if (srr1 & 0x40000) {
194 printk(KERN_ERR "I-side SLB multiple hit\n"); 273 printk(KERN_ERR "I-side SLB multiple hit\n");
274 dump_slb = 1;
275 }
276
195 if (srr1 & 0x20000) 277 if (srr1 & 0x20000)
196 printk(KERN_ERR "I-cache parity error hit\n"); 278 printk(KERN_ERR "I-cache parity error hit\n");
197 279
280 if (num_mce_regs == 0)
281 printk(KERN_ERR "No MCE registers mapped yet, can't dump\n");
282 else
283 printk(KERN_ERR "SoC debug registers:\n");
284
285 for (i = 0; i < num_mce_regs; i++)
286 printk(KERN_ERR "%s: 0x%08x\n", mce_regs[i].name,
287 in_le32(mce_regs[i].addr));
288
289 if (dump_slb) {
290 unsigned long e, v;
291 int i;
292
293 printk(KERN_ERR "slb contents:\n");
294 for (i = 0; i < SLB_NUM_ENTRIES; i++) {
295 asm volatile("slbmfee %0,%1" : "=r" (e) : "r" (i));
296 asm volatile("slbmfev %0,%1" : "=r" (v) : "r" (i));
297 printk(KERN_ERR "%02d %016lx %016lx\n", i, e, v);
298 }
299 }
300
301
198 /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ 302 /* SRR1[62] is from MSR[62] if recoverable, so pass that back */
199 return !!(srr1 & 0x2); 303 return !!(srr1 & 0x2);
200} 304}