aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/traps.c
diff options
context:
space:
mode:
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;