[PATCH 1/3] traps-cleanup
Jake Moilanen
moilanen at austin.ibm.com
Fri Dec 17 08:40:58 EST 2004
Clean-up of traps.c. Moved the machine dependent calls to a ppc_md call,
and moved the pSeries specific code to ras.c.
I also changed the naming convention to more closely follow the Linux
standards.
Signed-off-by: Jake Moilanen <moilanen at austin.ibm.com>
---
diff -puN arch/ppc64/kernel/traps.c~traps_cleanup arch/ppc64/kernel/traps.c
--- linux-2.6-bk/arch/ppc64/kernel/traps.c~traps_cleanup Tue Dec 14 17:05:09 2004
+++ linux-2.6-bk-moilanen/arch/ppc64/kernel/traps.c Wed Dec 15 10:11:23 2004
@@ -37,11 +37,7 @@
#include <asm/processor.h>
#include <asm/ppcdebug.h>
#include <asm/rtas.h>
-
-#ifdef CONFIG_PPC_PSERIES
-/* This is true if we are using the firmware NMI handler (typically LPAR) */
-extern int fwnmi_active;
-#endif
+#include <asm/machdep.h>
#ifdef CONFIG_DEBUGGER
int (*__debugger)(struct pt_regs *regs);
@@ -133,8 +129,7 @@ int die(const char *str, struct pt_regs
return 0;
}
-static void
-_exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
+void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
{
siginfo_t info;
@@ -150,53 +145,11 @@ _exception(int signr, struct pt_regs *re
force_sig_info(signr, &info, current);
}
-#ifdef CONFIG_PPC_PSERIES
-/* Get the error information for errors coming through the
- * FWNMI vectors. The pt_regs' r3 will be updated to reflect
- * the actual r3 if possible, and a ptr to the error log entry
- * will be returned if found.
- */
-static struct rtas_error_log *FWNMI_get_errinfo(struct pt_regs *regs)
-{
- unsigned long errdata = regs->gpr[3];
- struct rtas_error_log *errhdr = NULL;
- unsigned long *savep;
-
- if ((errdata >= 0x7000 && errdata < 0x7fff0) ||
- (errdata >= rtas.base && errdata < rtas.base + rtas.size - 16)) {
- savep = __va(errdata);
- regs->gpr[3] = savep[0]; /* restore original r3 */
- errhdr = (struct rtas_error_log *)(savep + 1);
- } else {
- printk("FWNMI: corrupt r3\n");
- }
- return errhdr;
-}
-
-/* Call this when done with the data returned by FWNMI_get_errinfo.
- * It will release the saved data area for other CPUs in the
- * partition to receive FWNMI errors.
- */
-static void FWNMI_release_errinfo(void)
-{
- int ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL);
- if (ret != 0)
- printk("FWNMI: nmi-interlock failed: %d\n", ret);
-}
-#endif
-
-void
-SystemResetException(struct pt_regs *regs)
+void system_reset_exception(struct pt_regs *regs)
{
-#ifdef CONFIG_PPC_PSERIES
- if (fwnmi_active) {
- struct rtas_error_log *errhdr = FWNMI_get_errinfo(regs);
- if (errhdr) {
- /* XXX Should look at FWNMI information */
- }
- FWNMI_release_errinfo();
- }
-#endif
+ /* See if any machine dependent calls */
+ if (ppc_md.system_reset_exception)
+ ppc_md.system_reset_exception(regs);
die("System Reset", regs, 0);
@@ -207,64 +160,16 @@ SystemResetException(struct pt_regs *reg
/* What should we do here? We could issue a shutdown or hard reset. */
}
-#ifdef CONFIG_PPC_PSERIES
-/*
- * See if we can recover from a machine check exception.
- * This is only called on power4 (or above) and only via
- * the Firmware Non-Maskable Interrupts (fwnmi) handler
- * which provides the error analysis for us.
- *
- * Return 1 if corrected (or delivered a signal).
- * Return 0 if there is nothing we can do.
- */
-static int recover_mce(struct pt_regs *regs, struct rtas_error_log err)
+void machine_check_exception(struct pt_regs *regs)
{
- if (err.disposition == RTAS_DISP_FULLY_RECOVERED) {
- /* Platform corrected itself */
- return 1;
- } else if ((regs->msr & MSR_RI) &&
- user_mode(regs) &&
- err.severity == RTAS_SEVERITY_ERROR_SYNC &&
- err.disposition == RTAS_DISP_NOT_RECOVERED &&
- err.target == RTAS_TARGET_MEMORY &&
- err.type == RTAS_TYPE_ECC_UNCORR &&
- !(current->pid == 0 || current->pid == 1)) {
- /* Kill off a user process with an ECC error */
- printk(KERN_ERR "MCE: uncorrectable ecc error for pid %d\n",
- current->pid);
- /* XXX something better for ECC error? */
- _exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
- return 1;
- }
- return 0;
-}
-#endif
+ int recover = 0;
+
+ /* See if any machine dependent calls */
+ if (ppc_md.machine_check_exception)
+ recover = ppc_md.machine_check_exception(regs);
-/*
- * Handle a machine check.
- *
- * Note that on Power 4 and beyond Firmware Non-Maskable Interrupts (fwnmi)
- * should be present. If so the handler which called us tells us if the
- * error was recovered (never true if RI=0).
- *
- * On hardware prior to Power 4 these exceptions were asynchronous which
- * means we can't tell exactly where it occurred and so we can't recover.
- */
-void
-MachineCheckException(struct pt_regs *regs)
-{
-#ifdef CONFIG_PPC_PSERIES
- struct rtas_error_log err, *errp;
-
- if (fwnmi_active) {
- errp = FWNMI_get_errinfo(regs);
- if (errp)
- err = *errp;
- FWNMI_release_errinfo(); /* frees errp */
- if (errp && recover_mce(regs, err))
- return;
- }
-#endif
+ if (recover)
+ return;
if (debugger_fault_handler(regs))
return;
@@ -275,8 +180,7 @@ MachineCheckException(struct pt_regs *re
panic("Unrecoverable Machine check");
}
-void
-UnknownException(struct pt_regs *regs)
+void unknown_exception(struct pt_regs *regs)
{
printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
regs->nip, regs->msr, regs->trap);
@@ -284,16 +188,14 @@ UnknownException(struct pt_regs *regs)
_exception(SIGTRAP, regs, 0, 0);
}
-void
-InstructionBreakpointException(struct pt_regs *regs)
+void instruction_breakpoint_exception(struct pt_regs *regs)
{
if (debugger_iabr_match(regs))
return;
_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
}
-void
-SingleStepException(struct pt_regs *regs)
+void single_step_exception(struct pt_regs *regs)
{
regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
@@ -312,7 +214,7 @@ SingleStepException(struct pt_regs *regs
static inline void emulate_single_step(struct pt_regs *regs)
{
if (regs->msr & MSR_SE)
- SingleStepException(regs);
+ single_step_exception(regs);
}
static void parse_fpe(struct pt_regs *regs)
@@ -456,8 +358,7 @@ check_bug_trap(struct pt_regs *regs)
return 0;
}
-void
-ProgramCheckException(struct pt_regs *regs)
+void program_check_exception(struct pt_regs *regs)
{
if (regs->msr & 0x100000) {
/* IEEE FP exception */
@@ -498,14 +399,14 @@ ProgramCheckException(struct pt_regs *re
}
}
-void KernelFPUnavailableException(struct pt_regs *regs)
+void kernel_fp_unavailable_exception(struct pt_regs *regs)
{
printk(KERN_EMERG "Unrecoverable FP Unavailable Exception "
"%lx at %lx\n", regs->trap, regs->nip);
die("Unrecoverable FP Unavailable Exception", regs, SIGABRT);
}
-void AltivecUnavailableException(struct pt_regs *regs)
+void altivec_unavailable_exception(struct pt_regs *regs)
{
#ifndef CONFIG_ALTIVEC
if (user_mode(regs)) {
@@ -536,14 +437,12 @@ void (*perf_irq)(struct pt_regs *) = dum
EXPORT_SYMBOL(perf_irq);
-void
-PerformanceMonitorException(struct pt_regs *regs)
+void performance_monitor_exception(struct pt_regs *regs)
{
perf_irq(regs);
}
-void
-AlignmentException(struct pt_regs *regs)
+void alignment_exception(struct pt_regs *regs)
{
int fixed;
@@ -571,8 +470,7 @@ AlignmentException(struct pt_regs *regs)
}
#ifdef CONFIG_ALTIVEC
-void
-AltivecAssistException(struct pt_regs *regs)
+void altivec_assist_exception(struct pt_regs *regs)
{
int err;
siginfo_t info;
diff -puN arch/ppc64/kernel/ras.c~traps_cleanup arch/ppc64/kernel/ras.c
--- linux-2.6-bk/arch/ppc64/kernel/ras.c~traps_cleanup Tue Dec 14 17:05:17 2004
+++ linux-2.6-bk-moilanen/arch/ppc64/kernel/ras.c Wed Dec 15 10:06:46 2004
@@ -55,6 +55,9 @@
static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX];
static spinlock_t ras_log_buf_lock = SPIN_LOCK_UNLOCKED;
+/* This is true if we are using the firmware NMI handler (typically LPAR) */
+extern int fwnmi_active;
+
static int ras_get_sensor_state_token;
static int ras_check_exception_token;
@@ -233,4 +236,105 @@ ras_error_interrupt(int irq, void *dev_i
spin_unlock(&ras_log_buf_lock);
return IRQ_HANDLED;
+}
+
+/* Get the error information for errors coming through the
+ * FWNMI vectors. The pt_regs' r3 will be updated to reflect
+ * the actual r3 if possible, and a ptr to the error log entry
+ * will be returned if found.
+ */
+static struct rtas_error_log *FWNMI_get_errinfo(struct pt_regs *regs)
+{
+ unsigned long errdata = regs->gpr[3];
+ struct rtas_error_log *errhdr = NULL;
+ unsigned long *savep;
+
+ if ((errdata >= 0x7000 && errdata < 0x7fff0) ||
+ (errdata >= rtas.base && errdata < rtas.base + rtas.size - 16)) {
+ savep = __va(errdata);
+ regs->gpr[3] = savep[0]; /* restore original r3 */
+ errhdr = (struct rtas_error_log *)(savep + 1);
+ } else {
+ printk("FWNMI: corrupt r3\n");
+ }
+ return errhdr;
+}
+
+/* Call this when done with the data returned by FWNMI_get_errinfo.
+ * It will release the saved data area for other CPUs in the
+ * partition to receive FWNMI errors.
+ */
+static void FWNMI_release_errinfo(void)
+{
+ int ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL);
+ if (ret != 0)
+ printk("FWNMI: nmi-interlock failed: %d\n", ret);
+}
+
+void pSeries_system_reset_exception(struct pt_regs *regs)
+{
+ if (fwnmi_active) {
+ struct rtas_error_log *errhdr = FWNMI_get_errinfo(regs);
+ if (errhdr) {
+ /* XXX Should look at FWNMI information */
+ }
+ FWNMI_release_errinfo();
+ }
+}
+
+/*
+ * See if we can recover from a machine check exception.
+ * This is only called on power4 (or above) and only via
+ * the Firmware Non-Maskable Interrupts (fwnmi) handler
+ * which provides the error analysis for us.
+ *
+ * Return 1 if corrected (or delivered a signal).
+ * Return 0 if there is nothing we can do.
+ */
+static int recover_mce(struct pt_regs *regs, struct rtas_error_log err)
+{
+ if (err.disposition == RTAS_DISP_FULLY_RECOVERED) {
+ /* Platform corrected itself */
+ return 1;
+ } else if ((regs->msr & MSR_RI) &&
+ user_mode(regs) &&
+ err.severity == RTAS_SEVERITY_ERROR_SYNC &&
+ err.disposition == RTAS_DISP_NOT_RECOVERED &&
+ err.target == RTAS_TARGET_MEMORY &&
+ err.type == RTAS_TYPE_ECC_UNCORR &&
+ !(current->pid == 0 || current->pid == 1)) {
+ /* Kill off a user process with an ECC error */
+ printk(KERN_ERR "MCE: uncorrectable ecc error for pid %d\n",
+ current->pid);
+ /* XXX something better for ECC error? */
+ _exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Handle a machine check.
+ *
+ * Note that on Power 4 and beyond Firmware Non-Maskable Interrupts (fwnmi)
+ * should be present. If so the handler which called us tells us if the
+ * error was recovered (never true if RI=0).
+ *
+ * On hardware prior to Power 4 these exceptions were asynchronous which
+ * means we can't tell exactly where it occurred and so we can't recover.
+ */
+int pSeries_machine_check_exception(struct pt_regs *regs)
+{
+ struct rtas_error_log err, *errp;
+
+ if (fwnmi_active) {
+ errp = FWNMI_get_errinfo(regs);
+ if (errp)
+ err = *errp;
+ FWNMI_release_errinfo(); /* frees errp */
+ if (errp && recover_mce(regs, err))
+ return 1;
+ }
+
+ return 0;
}
diff -puN arch/ppc64/kernel/head.S~traps_cleanup arch/ppc64/kernel/head.S
--- linux-2.6-bk/arch/ppc64/kernel/head.S~traps_cleanup Tue Dec 14 17:12:18 2004
+++ linux-2.6-bk-moilanen/arch/ppc64/kernel/head.S Tue Dec 14 17:29:44 2004
@@ -745,7 +745,7 @@ __end_stab:
/*** Common interrupt handlers ***/
- STD_EXCEPTION_COMMON(0x100, SystemReset, .SystemResetException)
+ STD_EXCEPTION_COMMON(0x100, SystemReset, .system_reset_exception)
/*
* Machine check is different because we use a different
@@ -758,20 +758,20 @@ MachineCheck_common:
DISABLE_INTS
bl .save_nvgprs
addi r3,r1,STACK_FRAME_OVERHEAD
- bl .MachineCheckException
+ bl .machine_check_exception
b .ret_from_except
STD_EXCEPTION_COMMON_LITE(0x900, Decrementer, .timer_interrupt)
- STD_EXCEPTION_COMMON(0xa00, Trap_0a, .UnknownException)
- STD_EXCEPTION_COMMON(0xb00, Trap_0b, .UnknownException)
- STD_EXCEPTION_COMMON(0xd00, SingleStep, .SingleStepException)
- STD_EXCEPTION_COMMON(0xe00, Trap_0e, .UnknownException)
- STD_EXCEPTION_COMMON(0xf00, PerformanceMonitor, .PerformanceMonitorException)
- STD_EXCEPTION_COMMON(0x1300, InstructionBreakpoint, .InstructionBreakpointException)
+ STD_EXCEPTION_COMMON(0xa00, Trap_0a, .unknown_exception)
+ STD_EXCEPTION_COMMON(0xb00, Trap_0b, .unknown_exception)
+ STD_EXCEPTION_COMMON(0xd00, SingleStep, .single_step_exception)
+ STD_EXCEPTION_COMMON(0xe00, Trap_0e, .unknown_exception)
+ STD_EXCEPTION_COMMON(0xf00, PerformanceMonitor, .performance_monitor_exception)
+ STD_EXCEPTION_COMMON(0x1300, InstructionBreakpoint, .instruction_breakpoint_exception)
#ifdef CONFIG_ALTIVEC
- STD_EXCEPTION_COMMON(0x1700, AltivecAssist, .AltivecAssistException)
+ STD_EXCEPTION_COMMON(0x1700, AltivecAssist, .altivec_assist_exception)
#else
- STD_EXCEPTION_COMMON(0x1700, AltivecAssist, .UnknownException)
+ STD_EXCEPTION_COMMON(0x1700, AltivecAssist, .unknown_exception)
#endif
/*
@@ -908,7 +908,7 @@ Alignment_common:
bl .save_nvgprs
addi r3,r1,STACK_FRAME_OVERHEAD
ENABLE_INTS
- bl .AlignmentException
+ bl .alignment_exception
b .ret_from_except
.align 7
@@ -918,7 +918,7 @@ ProgramCheck_common:
bl .save_nvgprs
addi r3,r1,STACK_FRAME_OVERHEAD
ENABLE_INTS
- bl .ProgramCheckException
+ bl .program_check_exception
b .ret_from_except
.align 7
@@ -929,7 +929,7 @@ FPUnavailable_common:
bl .save_nvgprs
addi r3,r1,STACK_FRAME_OVERHEAD
ENABLE_INTS
- bl .KernelFPUnavailableException
+ bl .kernel_fp_unavailable_exception
BUG_OPCODE
.align 7
@@ -942,7 +942,7 @@ AltivecUnavailable_common:
bl .save_nvgprs
addi r3,r1,STACK_FRAME_OVERHEAD
ENABLE_INTS
- bl .AltivecUnavailableException
+ bl .altivec_unavailable_exception
b .ret_from_except
/*
diff -puN include/asm-ppc64/machdep.h~traps_cleanup include/asm-ppc64/machdep.h
--- linux-2.6-bk/include/asm-ppc64/machdep.h~traps_cleanup Wed Dec 15 09:31:23 2004
+++ linux-2.6-bk-moilanen/include/asm-ppc64/machdep.h Wed Dec 15 10:07:00 2004
@@ -110,6 +110,10 @@ struct machdep_calls {
ssize_t (*nvram_size)(void);
int (*nvram_sync)(void);
+ /* Exception handlers */
+ void (*system_reset_exception)(struct pt_regs *regs);
+ int (*machine_check_exception)(struct pt_regs *regs);
+
/* Motherboard/chipset features. This is a kind of general purpose
* hook used to control some machine specific features (like reset
* lines, chip power control, etc...).
diff -puN arch/ppc64/kernel/pSeries_setup.c~traps_cleanup arch/ppc64/kernel/pSeries_setup.c
--- linux-2.6-bk/arch/ppc64/kernel/pSeries_setup.c~traps_cleanup Wed Dec 15 10:02:40 2004
+++ linux-2.6-bk-moilanen/arch/ppc64/kernel/pSeries_setup.c Wed Dec 15 10:13:32 2004
@@ -92,6 +92,9 @@ extern unsigned long loops_per_jiffy;
extern unsigned long ppc_proc_freq;
extern unsigned long ppc_tb_freq;
+extern void pSeries_system_reset_exception(struct pt_regs *regs);
+extern int pSeries_machine_check_exception(struct pt_regs *regs);
+
static volatile void __iomem * chrp_int_ack_special;
struct mpic *pSeries_mpic;
@@ -610,4 +613,6 @@ struct machdep_calls __initdata pSeries_
.calibrate_decr = pSeries_calibrate_decr,
.progress = pSeries_progress,
.check_legacy_ioport = pSeries_check_legacy_ioport,
+ .system_reset_exception = pSeries_system_reset_exception,
+ .machine_check_exception = pSeries_machine_check_exception,
};
_
More information about the Linuxppc64-dev
mailing list