diff options
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r-- | arch/powerpc/kernel/traps.c | 77 |
1 files changed, 46 insertions, 31 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 064a525..9b352bd 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -14,7 +14,6 @@ * This file handles the architecture-dependent parts of hardware exceptions */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -32,6 +31,7 @@ #include <linux/delay.h> #include <linux/kprobes.h> #include <linux/kexec.h> +#include <linux/backlight.h> #include <asm/kdebug.h> #include <asm/pgtable.h> @@ -51,6 +51,7 @@ #include <asm/firmware.h> #include <asm/processor.h> #endif +#include <asm/kexec.h> #ifdef CONFIG_PPC64 /* XXX */ #define _IO_BASE pci_io_base @@ -96,7 +97,7 @@ static DEFINE_SPINLOCK(die_lock); int die(const char *str, struct pt_regs *regs, long err) { - static int die_counter, crash_dump_start = 0; + static int die_counter; if (debugger(regs)) return 1; @@ -105,10 +106,18 @@ int die(const char *str, struct pt_regs *regs, long err) spin_lock_irq(&die_lock); bust_spinlocks(1); #ifdef CONFIG_PMAC_BACKLIGHT - if (machine_is(powermac)) { - set_backlight_enable(1); - set_backlight_level(BACKLIGHT_MAX); + mutex_lock(&pmac_backlight_mutex); + if (machine_is(powermac) && pmac_backlight) { + struct backlight_properties *props; + + down(&pmac_backlight->sem); + props = pmac_backlight->props; + props->brightness = props->max_brightness; + props->power = FB_BLANK_UNBLANK; + props->update_status(pmac_backlight); + up(&pmac_backlight->sem); } + mutex_unlock(&pmac_backlight_mutex); #endif printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); #ifdef CONFIG_PREEMPT @@ -128,32 +137,19 @@ int die(const char *str, struct pt_regs *regs, long err) print_modules(); show_regs(regs); bust_spinlocks(0); + spin_unlock_irq(&die_lock); - if (!crash_dump_start && kexec_should_crash(current)) { - crash_dump_start = 1; - spin_unlock_irq(&die_lock); + if (kexec_should_crash(current) || + kexec_sr_activated(smp_processor_id())) crash_kexec(regs); - /* NOTREACHED */ - } - spin_unlock_irq(&die_lock); - if (crash_dump_start) - /* - * Only for soft-reset: Other CPUs will be responded to an IPI - * sent by first kexec CPU. - */ - for(;;) - ; + crash_kexec_secondary(regs); if (in_interrupt()) panic("Fatal exception in interrupt"); - if (panic_on_oops) { -#ifdef CONFIG_PPC64 - printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); - ssleep(5); -#endif + if (panic_on_oops) panic("Fatal exception"); - } + do_exit(err); return 0; @@ -206,8 +202,25 @@ void system_reset_exception(struct pt_regs *regs) return; } +#ifdef CONFIG_KEXEC + cpu_set(smp_processor_id(), cpus_in_sr); +#endif + die("System Reset", regs, SIGABRT); + /* + * Some CPUs when released from the debugger will execute this path. + * These CPUs entered the debugger via a soft-reset. If the CPU was + * hung before entering the debugger it will return to the hung + * state when exiting this function. This causes a problem in + * kdump since the hung CPU(s) will not respond to the IPI sent + * from kdump. To prevent the problem we call crash_kexec_secondary() + * here. If a kdump had not been initiated or we exit the debugger + * with the "exit and recover" command (x) crash_kexec_secondary() + * will return after 5ms and the CPU returns to its previous state. + */ + crash_kexec_secondary(regs); + /* Must die if the interrupt is not recoverable */ if (!(regs->msr & MSR_RI)) panic("Unrecoverable System Reset"); @@ -572,14 +585,14 @@ static void parse_fpe(struct pt_regs *regs) #define INST_MFSPR_PVR_MASK 0xfc1fffff #define INST_DCBA 0x7c0005ec -#define INST_DCBA_MASK 0x7c0007fe +#define INST_DCBA_MASK 0xfc0007fe #define INST_MCRXR 0x7c000400 -#define INST_MCRXR_MASK 0x7c0007fe +#define INST_MCRXR_MASK 0xfc0007fe #define INST_STRING 0x7c00042a -#define INST_STRING_MASK 0x7c0007fe -#define INST_STRING_GEN_MASK 0x7c00067e +#define INST_STRING_MASK 0xfc0007fe +#define INST_STRING_GEN_MASK 0xfc00067e #define INST_LSWI 0x7c0004aa #define INST_LSWX 0x7c00042a #define INST_STSWI 0x7c0005aa @@ -658,7 +671,7 @@ static int emulate_instruction(struct pt_regs *regs) u32 instword; u32 rd; - if (!user_mode(regs)) + if (!user_mode(regs) || (regs->msr & MSR_LE)) return -EINVAL; CHECK_FULL_REGS(regs); @@ -805,9 +818,11 @@ void __kprobes program_check_exception(struct pt_regs *regs) void alignment_exception(struct pt_regs *regs) { - int fixed; + int fixed = 0; - fixed = fix_alignment(regs); + /* we don't implement logging of alignment exceptions */ + if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS)) + fixed = fix_alignment(regs); if (fixed == 1) { regs->nip += 4; /* skip over emulated instruction */ |