diff options
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r-- | arch/powerpc/kernel/traps.c | 52 |
1 files changed, 36 insertions, 16 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 6297da743db9..55d221ffcf1e 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -108,42 +108,62 @@ static void pmac_backlight_unblank(void) static inline void pmac_backlight_unblank(void) { } #endif -static DEFINE_SPINLOCK(die_lock); - int die(const char *str, struct pt_regs *regs, long err) { + static struct { + spinlock_t lock; + u32 lock_owner; + int lock_owner_depth; + } die = { + .lock = __SPIN_LOCK_UNLOCKED(die.lock), + .lock_owner = -1, + .lock_owner_depth = 0 + }; static int die_counter; + unsigned long flags; if (debugger(regs)) return 1; oops_enter(); - console_verbose(); - spin_lock_irq(&die_lock); - bust_spinlocks(1); - if (machine_is(powermac)) - pmac_backlight_unblank(); + if (die.lock_owner != raw_smp_processor_id()) { + console_verbose(); + spin_lock_irqsave(&die.lock, flags); + die.lock_owner = smp_processor_id(); + die.lock_owner_depth = 0; + bust_spinlocks(1); + if (machine_is(powermac)) + pmac_backlight_unblank(); + } else { + local_save_flags(flags); + } - printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); + if (++die.lock_owner_depth < 3) { + printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); #ifdef CONFIG_PREEMPT - printk("PREEMPT "); + printk("PREEMPT "); #endif #ifdef CONFIG_SMP - printk("SMP NR_CPUS=%d ", NR_CPUS); + printk("SMP NR_CPUS=%d ", NR_CPUS); #endif #ifdef CONFIG_DEBUG_PAGEALLOC - printk("DEBUG_PAGEALLOC "); + printk("DEBUG_PAGEALLOC "); #endif #ifdef CONFIG_NUMA - printk("NUMA "); + printk("NUMA "); #endif - printk("%s\n", ppc_md.name ? "" : ppc_md.name); + printk("%s\n", ppc_md.name ? "" : ppc_md.name); + + print_modules(); + show_regs(regs); + } else { + printk("Recursive die() failure, output suppressed\n"); + } - print_modules(); - show_regs(regs); bust_spinlocks(0); - spin_unlock_irq(&die_lock); + die.lock_owner = -1; + spin_unlock_irqrestore(&die.lock, flags); if (kexec_should_crash(current) || kexec_sr_activated(smp_processor_id())) |