aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/traps.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2005-08-29 15:45:11 -0400
committerDavid S. Miller <davem@davemloft.net>2005-08-29 15:45:11 -0400
commit6c52a96e6cacb35403b85c3b42db0faf26f3ed85 (patch)
tree07ebe2ce68511ffb75575603b0c58bf00c78f8c7 /arch/sparc64/kernel/traps.c
parentbde4e4ee9f90142d550e2684dec2c8df302f5f8e (diff)
[SPARC64]: Revamp Spitfire error trap handling.
Current uncorrectable error handling was poor enough that the processor could just loop taking the same trap over and over again. Fix things up so that we at least get a log message and perhaps even some register state. In the process, much consolidation became possible, particularly with the correctable error handler. Prefix assembler and C function names with "spitfire" to indicate that these are for Ultra-I/II/IIi/IIe only. More work is needed to make these routines robust and featureful to the level of the Ultra-III error handlers. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/traps.c')
-rw-r--r--arch/sparc64/kernel/traps.c264
1 files changed, 145 insertions, 119 deletions
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 210b3e321c29..b280b2ef674f 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -33,6 +33,7 @@
33#include <asm/dcu.h> 33#include <asm/dcu.h>
34#include <asm/estate.h> 34#include <asm/estate.h>
35#include <asm/chafsr.h> 35#include <asm/chafsr.h>
36#include <asm/sfafsr.h>
36#include <asm/psrcompat.h> 37#include <asm/psrcompat.h>
37#include <asm/processor.h> 38#include <asm/processor.h>
38#include <asm/timer.h> 39#include <asm/timer.h>
@@ -143,8 +144,7 @@ void do_BUG(const char *file, int line)
143} 144}
144#endif 145#endif
145 146
146void instruction_access_exception(struct pt_regs *regs, 147void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
147 unsigned long sfsr, unsigned long sfar)
148{ 148{
149 siginfo_t info; 149 siginfo_t info;
150 150
@@ -153,8 +153,8 @@ void instruction_access_exception(struct pt_regs *regs,
153 return; 153 return;
154 154
155 if (regs->tstate & TSTATE_PRIV) { 155 if (regs->tstate & TSTATE_PRIV) {
156 printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n", 156 printk("spitfire_insn_access_exception: SFSR[%016lx] "
157 sfsr, sfar); 157 "SFAR[%016lx], going.\n", sfsr, sfar);
158 die_if_kernel("Iax", regs); 158 die_if_kernel("Iax", regs);
159 } 159 }
160 if (test_thread_flag(TIF_32BIT)) { 160 if (test_thread_flag(TIF_32BIT)) {
@@ -169,19 +169,17 @@ void instruction_access_exception(struct pt_regs *regs,
169 force_sig_info(SIGSEGV, &info, current); 169 force_sig_info(SIGSEGV, &info, current);
170} 170}
171 171
172void instruction_access_exception_tl1(struct pt_regs *regs, 172void spitfire_insn_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
173 unsigned long sfsr, unsigned long sfar)
174{ 173{
175 if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs, 174 if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs,
176 0, 0x8, SIGTRAP) == NOTIFY_STOP) 175 0, 0x8, SIGTRAP) == NOTIFY_STOP)
177 return; 176 return;
178 177
179 dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); 178 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
180 instruction_access_exception(regs, sfsr, sfar); 179 spitfire_insn_access_exception(regs, sfsr, sfar);
181} 180}
182 181
183void data_access_exception(struct pt_regs *regs, 182void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
184 unsigned long sfsr, unsigned long sfar)
185{ 183{
186 siginfo_t info; 184 siginfo_t info;
187 185
@@ -207,8 +205,8 @@ void data_access_exception(struct pt_regs *regs,
207 return; 205 return;
208 } 206 }
209 /* Shit... */ 207 /* Shit... */
210 printk("data_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n", 208 printk("spitfire_data_access_exception: SFSR[%016lx] "
211 sfsr, sfar); 209 "SFAR[%016lx], going.\n", sfsr, sfar);
212 die_if_kernel("Dax", regs); 210 die_if_kernel("Dax", regs);
213 } 211 }
214 212
@@ -220,15 +218,14 @@ void data_access_exception(struct pt_regs *regs,
220 force_sig_info(SIGSEGV, &info, current); 218 force_sig_info(SIGSEGV, &info, current);
221} 219}
222 220
223void data_access_exception_tl1(struct pt_regs *regs, 221void spitfire_data_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
224 unsigned long sfsr, unsigned long sfar)
225{ 222{
226 if (notify_die(DIE_TRAP_TL1, "data access exception tl1", regs, 223 if (notify_die(DIE_TRAP_TL1, "data access exception tl1", regs,
227 0, 0x30, SIGTRAP) == NOTIFY_STOP) 224 0, 0x30, SIGTRAP) == NOTIFY_STOP)
228 return; 225 return;
229 226
230 dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); 227 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
231 data_access_exception(regs, sfsr, sfar); 228 spitfire_data_access_exception(regs, sfsr, sfar);
232} 229}
233 230
234#ifdef CONFIG_PCI 231#ifdef CONFIG_PCI
@@ -264,54 +261,13 @@ static void spitfire_clean_and_reenable_l1_caches(void)
264 : "memory"); 261 : "memory");
265} 262}
266 263
267void do_iae(struct pt_regs *regs) 264static void spitfire_enable_estate_errors(void)
268{ 265{
269 siginfo_t info; 266 __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
270 267 "membar #Sync"
271 spitfire_clean_and_reenable_l1_caches(); 268 : /* no outputs */
272 269 : "r" (ESTATE_ERR_ALL),
273 if (notify_die(DIE_TRAP, "instruction access exception", regs, 270 "i" (ASI_ESTATE_ERROR_EN));
274 0, 0x8, SIGTRAP) == NOTIFY_STOP)
275 return;
276
277 info.si_signo = SIGBUS;
278 info.si_errno = 0;
279 info.si_code = BUS_OBJERR;
280 info.si_addr = (void *)0;
281 info.si_trapno = 0;
282 force_sig_info(SIGBUS, &info, current);
283}
284
285void do_dae(struct pt_regs *regs)
286{
287 siginfo_t info;
288
289#ifdef CONFIG_PCI
290 if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
291 spitfire_clean_and_reenable_l1_caches();
292
293 pci_poke_faulted = 1;
294
295 /* Why the fuck did they have to change this? */
296 if (tlb_type == cheetah || tlb_type == cheetah_plus)
297 regs->tpc += 4;
298
299 regs->tnpc = regs->tpc + 4;
300 return;
301 }
302#endif
303 spitfire_clean_and_reenable_l1_caches();
304
305 if (notify_die(DIE_TRAP, "data access exception", regs,
306 0, 0x30, SIGTRAP) == NOTIFY_STOP)
307 return;
308
309 info.si_signo = SIGBUS;
310 info.si_errno = 0;
311 info.si_code = BUS_OBJERR;
312 info.si_addr = (void *)0;
313 info.si_trapno = 0;
314 force_sig_info(SIGBUS, &info, current);
315} 271}
316 272
317static char ecc_syndrome_table[] = { 273static char ecc_syndrome_table[] = {
@@ -349,65 +305,15 @@ static char ecc_syndrome_table[] = {
349 0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a 305 0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a
350}; 306};
351 307
352/* cee_trap in entry.S encodes AFSR/UDBH/UDBL error status
353 * in the following format. The AFAR is left as is, with
354 * reserved bits cleared, and is a raw 40-bit physical
355 * address.
356 */
357#define CE_STATUS_UDBH_UE (1UL << (43 + 9))
358#define CE_STATUS_UDBH_CE (1UL << (43 + 8))
359#define CE_STATUS_UDBH_ESYNDR (0xffUL << 43)
360#define CE_STATUS_UDBH_SHIFT 43
361#define CE_STATUS_UDBL_UE (1UL << (33 + 9))
362#define CE_STATUS_UDBL_CE (1UL << (33 + 8))
363#define CE_STATUS_UDBL_ESYNDR (0xffUL << 33)
364#define CE_STATUS_UDBL_SHIFT 33
365#define CE_STATUS_AFSR_MASK (0x1ffffffffUL)
366#define CE_STATUS_AFSR_ME (1UL << 32)
367#define CE_STATUS_AFSR_PRIV (1UL << 31)
368#define CE_STATUS_AFSR_ISAP (1UL << 30)
369#define CE_STATUS_AFSR_ETP (1UL << 29)
370#define CE_STATUS_AFSR_IVUE (1UL << 28)
371#define CE_STATUS_AFSR_TO (1UL << 27)
372#define CE_STATUS_AFSR_BERR (1UL << 26)
373#define CE_STATUS_AFSR_LDP (1UL << 25)
374#define CE_STATUS_AFSR_CP (1UL << 24)
375#define CE_STATUS_AFSR_WP (1UL << 23)
376#define CE_STATUS_AFSR_EDP (1UL << 22)
377#define CE_STATUS_AFSR_UE (1UL << 21)
378#define CE_STATUS_AFSR_CE (1UL << 20)
379#define CE_STATUS_AFSR_ETS (0xfUL << 16)
380#define CE_STATUS_AFSR_ETS_SHIFT 16
381#define CE_STATUS_AFSR_PSYND (0xffffUL << 0)
382#define CE_STATUS_AFSR_PSYND_SHIFT 0
383
384/* Layout of Ecache TAG Parity Syndrome of AFSR */
385#define AFSR_ETSYNDROME_7_0 0x1UL /* E$-tag bus bits <7:0> */
386#define AFSR_ETSYNDROME_15_8 0x2UL /* E$-tag bus bits <15:8> */
387#define AFSR_ETSYNDROME_21_16 0x4UL /* E$-tag bus bits <21:16> */
388#define AFSR_ETSYNDROME_24_22 0x8UL /* E$-tag bus bits <24:22> */
389
390static char *syndrome_unknown = "<Unknown>"; 308static char *syndrome_unknown = "<Unknown>";
391 309
392asmlinkage void cee_log(unsigned long ce_status, 310static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long bit)
393 unsigned long afar,
394 struct pt_regs *regs)
395{ 311{
396 char memmod_str[64]; 312 unsigned short scode;
397 char *p; 313 char memmod_str[64], *p;
398 unsigned short scode, udb_reg;
399 314
400 printk(KERN_WARNING "CPU[%d]: Correctable ECC Error " 315 if (udbl & bit) {
401 "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx]\n", 316 scode = ecc_syndrome_table[udbl & 0xff];
402 smp_processor_id(),
403 (ce_status & CE_STATUS_AFSR_MASK),
404 afar,
405 ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL),
406 ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL));
407
408 udb_reg = ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL);
409 if (udb_reg & (1 << 8)) {
410 scode = ecc_syndrome_table[udb_reg & 0xff];
411 if (prom_getunumber(scode, afar, 317 if (prom_getunumber(scode, afar,
412 memmod_str, sizeof(memmod_str)) == -1) 318 memmod_str, sizeof(memmod_str)) == -1)
413 p = syndrome_unknown; 319 p = syndrome_unknown;
@@ -418,9 +324,8 @@ asmlinkage void cee_log(unsigned long ce_status,
418 smp_processor_id(), scode, p); 324 smp_processor_id(), scode, p);
419 } 325 }
420 326
421 udb_reg = ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL); 327 if (udbh & bit) {
422 if (udb_reg & (1 << 8)) { 328 scode = ecc_syndrome_table[udbh & 0xff];
423 scode = ecc_syndrome_table[udb_reg & 0xff];
424 if (prom_getunumber(scode, afar, 329 if (prom_getunumber(scode, afar,
425 memmod_str, sizeof(memmod_str)) == -1) 330 memmod_str, sizeof(memmod_str)) == -1)
426 p = syndrome_unknown; 331 p = syndrome_unknown;
@@ -430,6 +335,127 @@ asmlinkage void cee_log(unsigned long ce_status,
430 "Memory Module \"%s\"\n", 335 "Memory Module \"%s\"\n",
431 smp_processor_id(), scode, p); 336 smp_processor_id(), scode, p);
432 } 337 }
338
339}
340
341static void spitfire_cee_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, int tl1, struct pt_regs *regs)
342{
343
344 printk(KERN_WARNING "CPU[%d]: Correctable ECC Error "
345 "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx] TL>1[%d]\n",
346 smp_processor_id(), afsr, afar, udbl, udbh, tl1);
347
348 spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_CE);
349
350 /* We always log it, even if someone is listening for this
351 * trap.
352 */
353 notify_die(DIE_TRAP, "Correctable ECC Error", regs,
354 0, TRAP_TYPE_CEE, SIGTRAP);
355
356 /* The Correctable ECC Error trap does not disable I/D caches. So
357 * we only have to restore the ESTATE Error Enable register.
358 */
359 spitfire_enable_estate_errors();
360}
361
362static void spitfire_ue_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long tt, int tl1, struct pt_regs *regs)
363{
364 siginfo_t info;
365
366 printk(KERN_WARNING "CPU[%d]: Uncorrectable Error AFSR[%lx] "
367 "AFAR[%lx] UDBL[%lx] UDBH[%ld] TT[%lx] TL>1[%d]\n",
368 smp_processor_id(), afsr, afar, udbl, udbh, tt, tl1);
369
370 /* XXX add more human friendly logging of the error status
371 * XXX as is implemented for cheetah
372 */
373
374 spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_UE);
375
376 /* We always log it, even if someone is listening for this
377 * trap.
378 */
379 notify_die(DIE_TRAP, "Uncorrectable Error", regs,
380 0, tt, SIGTRAP);
381
382 if (regs->tstate & TSTATE_PRIV) {
383 if (tl1)
384 dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
385 die_if_kernel("UE", regs);
386 }
387
388 /* XXX need more intelligent processing here, such as is implemented
389 * XXX for cheetah errors, in fact if the E-cache still holds the
390 * XXX line with bad parity this will loop
391 */
392
393 spitfire_clean_and_reenable_l1_caches();
394 spitfire_enable_estate_errors();
395
396 if (test_thread_flag(TIF_32BIT)) {
397 regs->tpc &= 0xffffffff;
398 regs->tnpc &= 0xffffffff;
399 }
400 info.si_signo = SIGBUS;
401 info.si_errno = 0;
402 info.si_code = BUS_OBJERR;
403 info.si_addr = (void *)0;
404 info.si_trapno = 0;
405 force_sig_info(SIGBUS, &info, current);
406}
407
408void spitfire_access_error(struct pt_regs *regs, unsigned long status_encoded, unsigned long afar)
409{
410 unsigned long afsr, tt, udbh, udbl;
411 int tl1;
412
413 afsr = (status_encoded & SFSTAT_AFSR_MASK) >> SFSTAT_AFSR_SHIFT;
414 tt = (status_encoded & SFSTAT_TRAP_TYPE) >> SFSTAT_TRAP_TYPE_SHIFT;
415 tl1 = (status_encoded & SFSTAT_TL_GT_ONE) ? 1 : 0;
416 udbl = (status_encoded & SFSTAT_UDBL_MASK) >> SFSTAT_UDBL_SHIFT;
417 udbh = (status_encoded & SFSTAT_UDBH_MASK) >> SFSTAT_UDBH_SHIFT;
418
419#ifdef CONFIG_PCI
420 if (tt == TRAP_TYPE_DAE &&
421 pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) {
422 spitfire_clean_and_reenable_l1_caches();
423 spitfire_enable_estate_errors();
424
425 pci_poke_faulted = 1;
426 regs->tnpc = regs->tpc + 4;
427 return;
428 }
429#endif
430
431 if (afsr & SFAFSR_UE)
432 spitfire_ue_log(afsr, afar, udbh, udbl, tt, tl1, regs);
433
434 if (tt == TRAP_TYPE_CEE) {
435 /* Handle the case where we took a CEE trap, but ACK'd
436 * only the UE state in the UDB error registers.
437 */
438 if (afsr & SFAFSR_UE) {
439 if (udbh & UDBE_CE) {
440 __asm__ __volatile__(
441 "stxa %0, [%1] %2\n\t"
442 "membar #Sync"
443 : /* no outputs */
444 : "r" (udbh & UDBE_CE),
445 "r" (0x0), "i" (ASI_UDB_ERROR_W));
446 }
447 if (udbl & UDBE_CE) {
448 __asm__ __volatile__(
449 "stxa %0, [%1] %2\n\t"
450 "membar #Sync"
451 : /* no outputs */
452 : "r" (udbl & UDBE_CE),
453 "r" (0x18), "i" (ASI_UDB_ERROR_W));
454 }
455 }
456
457 spitfire_cee_log(afsr, afar, udbh, udbl, tl1, regs);
458 }
433} 459}
434 460
435int cheetah_pcache_forced_on; 461int cheetah_pcache_forced_on;