summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMarius Strobl <marius@FreeBSD.org>2010-04-05 18:22:48 +0000
committerMarius Strobl <marius@FreeBSD.org>2010-04-05 18:22:48 +0000
commit8d6acfc69de85378103885874c280c690110c054 (patch)
tree723bc22565b8ea8989da2217dd9580b1b22c358a /sys
parent6d07d8a8ba33de41c3db34be896ef07cf555d1f7 (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/sparc64/sparc64/trap.c56
1 files changed, 51 insertions, 5 deletions
diff --git a/sys/sparc64/sparc64/trap.c b/sys/sparc64/sparc64/trap.c
index eddf5a2ee361..64dd751f3a36 100644
--- a/sys/sparc64/sparc64/trap.c
+++ b/sys/sparc64/sparc64/trap.c
@@ -95,6 +95,7 @@ __FBSDID("$FreeBSD$");
void trap(struct trapframe *tf);
void syscall(struct trapframe *tf);
+static int trap_cecc(void);
static int trap_pfault(struct thread *td, struct trapframe *tf);
extern char copy_fault[];
@@ -229,6 +230,10 @@ int debugger_on_signal = 0;
SYSCTL_INT(_debug, OID_AUTO, debugger_on_signal, CTLFLAG_RW,
&debugger_on_signal, 0, "");
+u_int corrected_ecc = 0;
+SYSCTL_UINT(_machdep, OID_AUTO, corrected_ecc, CTLFLAG_RD, &corrected_ecc, 0,
+ "corrected ECC errors");
+
/*
* SUNW,set-trap-table allows to take over %tba from the PROM, which
* will turn off interrupts and handle outstanding ones while doing so,
@@ -297,10 +302,16 @@ trap(struct trapframe *tf)
case T_SPILL:
sig = rwindow_save(td);
break;
+ case T_CORRECTED_ECC_ERROR:
+ sig = trap_cecc();
+ break;
default:
- if (tf->tf_type < 0 || tf->tf_type >= T_MAX ||
- trap_sig[tf->tf_type] == -1)
- panic("trap: bad trap type");
+ if (tf->tf_type < 0 || tf->tf_type >= T_MAX)
+ panic("trap: bad trap type %#lx (user)",
+ tf->tf_type);
+ else if (trap_sig[tf->tf_type] == -1)
+ panic("trap: %s (user)",
+ trap_msg[tf->tf_type]);
sig = trap_sig[tf->tf_type];
break;
}
@@ -389,18 +400,53 @@ trap(struct trapframe *tf)
}
error = 1;
break;
+ case T_CORRECTED_ECC_ERROR:
+ error = trap_cecc();
+ break;
default:
error = 1;
break;
}
- if (error != 0)
- panic("trap: %s", trap_msg[tf->tf_type & ~T_KERNEL]);
+ if (error != 0) {
+ tf->tf_type &= ~T_KERNEL;
+ if (tf->tf_type < 0 || tf->tf_type >= T_MAX)
+ panic("trap: bad trap type %#lx (kernel)",
+ tf->tf_type);
+ else if (trap_sig[tf->tf_type] == -1)
+ panic("trap: %s (kernel)",
+ trap_msg[tf->tf_type]);
+ }
}
CTR1(KTR_TRAP, "trap: td=%p return", td);
}
static int
+trap_cecc(void)
+{
+ u_long eee;
+
+ /*
+ * Turn off (non-)correctable error reporting while we're dealing
+ * with the error.
+ */
+ eee = ldxa(0, ASI_ESTATE_ERROR_EN_REG);
+ stxa_sync(0, ASI_ESTATE_ERROR_EN_REG, eee & ~(AA_ESTATE_NCEEN |
+ AA_ESTATE_CEEN));
+ /* Flush the caches in order ensure no corrupt data got installed. */
+ cache_flush();
+ /* Ensure the caches are still turned on (should be). */
+ cache_enable(PCPU_GET(impl));
+ /* Clear the the error from the AFSR. */
+ stxa_sync(0, ASI_AFSR, ldxa(0, ASI_AFSR));
+ corrected_ecc++;
+ printf("corrected ECC error\n");
+ /* Turn (non-)correctable error reporting back on. */
+ stxa_sync(0, ASI_ESTATE_ERROR_EN_REG, eee);
+ return (0);
+}
+
+static int
trap_pfault(struct thread *td, struct trapframe *tf)
{
struct vmspace *vm;