Messages in this thread Patch in this message | | | Date | Wed, 29 Dec 1999 22:22:11 +0100 (CET) | From | Andrea Arcangeli <> | Subject | Re: wait_on_irq, CPU1 |
| |
On Wed, 29 Dec 1999, Manfred Spraul wrote:
>This fix is incomplete: a few lines later 4095 is used again.
In my previous mail I have not quoted all the changes. These are the complete i386/*/traps.c changes in 2.2.13-ikd1.bz2:
diff -urN 2.2.13/arch/i386/kernel/traps.c 2.2.13-ikd/arch/i386/kernel/traps.c --- 2.2.13/arch/i386/kernel/traps.c Sun Oct 31 23:31:21 1999 +++ 2.2.13-ikd/arch/i386/kernel/traps.c Wed Nov 10 19:03:24 1999 @@ -2,6 +2,8 @@ * linux/arch/i386/traps.c * * Copyright (C) 1991, 1992 Linus Torvalds + * + * 1998, Ingo Molnar, added NMI-Watchdog driver */ /* @@ -20,12 +22,18 @@ #include <linux/smp_lock.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/kernel_stat.h> /* NMI oopser watchdog */ +#include <linux/profiler.h> /* mcount debugger */ #ifdef CONFIG_MCA #include <linux/mca.h> #include <asm/processor.h> #endif +#if defined(CONFIG_KDB) +#include <linux/kdb.h> +#endif + #include <asm/system.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -45,6 +53,9 @@ #include "irq.h" asmlinkage int system_call(void); +#if defined(CONFIG_KDB) +asmlinkage int kdb_call(void); +#endif asmlinkage void lcall7(void); struct desc_struct default_ldt = { 0, 0 }; @@ -117,9 +128,55 @@ * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is * a guess of how much space is likely to be vmalloced. */ -#define VMALLOC_OFFSET (8*1024*1024) #define MODULE_RANGE (8*1024*1024) +#ifdef CONFIG_KERNEL_DEBUGGING +inline void print_call_trace_exact (struct pt_regs * regs, unsigned long esp) +{ + int i=1; + unsigned long *this_stack, *prev_stack, prev_addr, *prev_bp, framesize; + + printk("\nCall Trace: "); + + /* + * the stack layout: /----- *this_stack + * V + * [this_frame][prev_bp][prev_addr][prev_frame][...] + */ + + this_stack = (unsigned long *) regs->ebp; + framesize=0; + + while ((unsigned long) this_stack >= (esp & ~0x1fffUL) && + (unsigned long) (this_stack+1) < + (esp & ~0x1fffUL)+0x2000UL) + { + prev_addr = *(this_stack+1); + + if (!(i++ % 8)) + printk("\n "); + /* ksymoops expects [<xxx>] */ + printk("[<%08lx>] (%lu) ", prev_addr, framesize); + + prev_bp = (unsigned long *)(*this_stack); + prev_stack = this_stack; + this_stack = prev_bp; + + if (i > 100) + { + printk("WARNING: something fishy with the stack frame?\n"); + printk("this_stack: [<%08lx>]\n", + (unsigned long)this_stack); + break; + } + framesize = (unsigned long)this_stack-(unsigned long)prev_stack; + } +#ifdef CONFIG_TRACE + print_emergency_trace(); +#endif +} +#endif /* CONFIG_KERNEL_DEBUGGING */ + static void show_registers(struct pt_regs *regs) { int i; @@ -155,19 +212,27 @@ printk("\nStack: "); stack = (unsigned long *) esp; for(i=0; i < kstack_depth_to_print; i++) { - if (((long) stack & 4095) == 0) + if (((long) stack & 8191) == 0) break; if (i && ((i % 8) == 0)) printk("\n "); printk("%08lx ", *stack++); } + +/* + * If tracing is switched on then we can walk the stack frame. Otherwise we + * can only guess. + */ +#ifdef CONFIG_KERNEL_DEBUGGING + print_call_trace_exact(regs, esp); +#else printk("\nCall Trace: "); stack = (unsigned long *) esp; i = 1; module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT); module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)); module_end = module_start + MODULE_RANGE; - while (((long) stack & 4095) != 0) { + while (((long) stack & 8191) != 0) { addr = *stack++; /* * If the address is either in the text segment of the @@ -186,6 +251,7 @@ i++; } } +#endif /* CONFIG_KERNEL_DEBUGGING */ printk("\nCode: "); for(i=0;i<20;i++) printk("%02x ", ((unsigned char *)regs->eip)[i]); @@ -199,6 +265,9 @@ { console_verbose(); spin_lock_irq(&die_lock); +#if defined(CONFIG_KDB) + kdb(KDB_REASON_PANIC, err, regs); +#endif printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); spin_unlock_irq(&die_lock); @@ -285,6 +354,7 @@ } } +#ifndef CONFIG_NMI_WATCHDOG static void mem_parity_error(unsigned char reason, struct pt_regs * regs) { printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n"); @@ -335,6 +405,73 @@ if (!(reason & 0xc0)) unknown_nmi_error(reason, regs); } +#else /* CONFIG_NMI_WATCHDOG */ + +extern atomic_t nmi_counter; + +/* + * FIXME: we assume here that the NMI came from the IO-APIC. It's a quite safe + * assumption in most cases, but if anyone knows a way to distinguish between + * NMI reasons, please speak up ... [i doubt that the IO-APIC does IO port 0x61 + * correctly] + */ + +extern atomic_t apic_timer_irqs [NR_CPUS]; +extern spinlock_t console_lock; +static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; + +asmlinkage void do_nmi(struct pt_regs * regs, long error_code) +{ + /* + * the best way to detect wether a CPU has a 'hard lockup' problem + * is to check it's local APIC timer IRQ counts. If they are not + * changing then that CPU has some problem. + * + * as these watchdog NMI IRQs are broadcasted to every CPU, here + * we only have to check the current processor. + * + * since NMIs dont listen to _any_ locks, we have to be extremely + * careful not to rely on unsafe variables. The printk might lock + * up though, so we have to break up console_lock first ... + * [when there will be more tty-related locks, break them up + * here too!] + */ + + static atomic_t last_irq_sums [NR_CPUS] = { ATOMIC_INIT(0), }; + static atomic_t alert_counter [NR_CPUS] = { ATOMIC_INIT(0), }; + + /* + * Since current-> is always on the stack, and we always switch + * the stack NMI-atomically, it's safe to use smp_processor_id(). + */ + int sum, cpu = smp_processor_id(); + + atomic_inc(&nmi_counter); + sum = atomic_read(apic_timer_irqs+cpu); + + if (atomic_read(last_irq_sums+cpu) == sum) { + /* + * Ayiee, looks like this CPU is stuck ... + * wait a few IRQs (5 seconds) before doing the oops ... + */ + atomic_inc(alert_counter+cpu); + if (atomic_read(alert_counter+cpu) == HZ/10) { +#ifdef CONFIG_DEBUG_MCOUNT + extern int sysctl_disable_mcount; + sysctl_disable_mcount = 1; +#endif + spin_lock(&nmi_print_lock); + printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu); + show_registers(regs); + spin_unlock(&nmi_print_lock); + do_exit(SIGSEGV); + } + } else { + atomic_set(last_irq_sums+cpu,sum); + atomic_set(alert_counter+cpu,0); + } +} +#endif /* CONFIG_NMI_WATCHDOG */ /* * Careful - we must not do a lock-kernel until we have checked that the @@ -397,9 +534,15 @@ return; clear_dr7: + +#if defined(CONFIG_KDB) + kdb(KDB_REASON_DEBUG, error_code, regs); +#else + __asm__("movl %0,%%db7" : /* no output */ : "r" (0)); +#endif /* CONFIG_KDB */ return; clear_TF: @@ -692,6 +835,13 @@ set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); set_system_gate(SYSCALL_VECTOR,&system_call); +#if defined(CONFIG_KDB) + /* + * A trap gate, used by the kernel to enter the + * debugger preserving all registers. + */ + set_trap_gate(KDBENTER_VECTOR,&kdb_call); +#endif /* set up GDT task & ldt entries */ set_tss_desc(0, &init_task.tss); Andrea
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |