[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Pull nmi/traps changes from Linux 2.6.14.
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxx # Node ID db500b8cb79acbce4a03cee0b10b0445a9ea1558 # Parent 06b80b837c92b5d6f6a50a2a569313293659d8f5 Pull nmi/traps changes from Linux 2.6.14. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> diff -r 06b80b837c92 -r db500b8cb79a xen/arch/x86/nmi.c --- a/xen/arch/x86/nmi.c Tue Dec 6 16:40:50 2005 +++ b/xen/arch/x86/nmi.c Tue Dec 6 16:48:57 2005 @@ -9,7 +9,8 @@ * Mikael Pettersson : AMD K7 support for local APIC NMI watchdog. * Mikael Pettersson : Power Management for local APIC NMI watchdog. * Mikael Pettersson : Pentium 4 support for local APIC NMI watchdog. - * Keir Fraser : Pentium 4 Hyperthreading support + * Pavel Machek and + * Mikael Pettersson : PM converted to driver model. Disable/enable API. */ #include <xen/config.h> @@ -27,6 +28,7 @@ #include <asm/msr.h> #include <asm/mpspec.h> #include <asm/debugger.h> +#include <asm/div64.h> unsigned int nmi_watchdog = NMI_NONE; static unsigned int nmi_hz = HZ; @@ -34,6 +36,28 @@ static unsigned int nmi_p4_cccr_val; static struct ac_timer nmi_timer[NR_CPUS]; static unsigned int nmi_timer_ticks[NR_CPUS]; + +/* + * lapic_nmi_owner tracks the ownership of the lapic NMI hardware: + * - it may be reserved by some other driver, or not + * - when not reserved by some other driver, it may be used for + * the NMI watchdog, or not + * + * This is maintained separately from nmi_active because the NMI + * watchdog may also be driven from the I/O APIC timer. + */ +static DEFINE_SPINLOCK(lapic_nmi_owner_lock); +static unsigned int lapic_nmi_owner; +#define LAPIC_NMI_WATCHDOG (1<<0) +#define LAPIC_NMI_RESERVED (1<<1) + +/* nmi_active: + * +1: the lapic NMI watchdog is active, but can be disabled + * 0: the lapic NMI watchdog has not been set up, and cannot + * be enabled + * -1: the lapic NMI watchdog is disabled, but can be enabled + */ +int nmi_active; #define K7_EVNTSEL_ENABLE (1 << 22) #define K7_EVNTSEL_INT (1 << 20) @@ -111,8 +135,73 @@ set_ac_timer(&nmi_timer[cpu], NOW() + MILLISECS(1000)); } -static inline void nmi_pm_init(void) { } -#define __pminit __init +static void disable_lapic_nmi_watchdog(void) +{ + if (nmi_active <= 0) + return; + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + wrmsr(MSR_K7_EVNTSEL0, 0, 0); + break; + case X86_VENDOR_INTEL: + switch (boot_cpu_data.x86) { + case 6: + if (boot_cpu_data.x86_model > 0xd) + break; + + wrmsr(MSR_P6_EVNTSEL0, 0, 0); + break; + case 15: + if (boot_cpu_data.x86_model > 0x4) + break; + + wrmsr(MSR_P4_IQ_CCCR0, 0, 0); + wrmsr(MSR_P4_CRU_ESCR0, 0, 0); + break; + } + break; + } + nmi_active = -1; + /* tell do_nmi() and others that we're not active any more */ + nmi_watchdog = 0; +} + +static void enable_lapic_nmi_watchdog(void) +{ + if (nmi_active < 0) { + nmi_watchdog = NMI_LOCAL_APIC; + setup_apic_nmi_watchdog(); + } +} + +int reserve_lapic_nmi(void) +{ + unsigned int old_owner; + + spin_lock(&lapic_nmi_owner_lock); + old_owner = lapic_nmi_owner; + lapic_nmi_owner |= LAPIC_NMI_RESERVED; + spin_unlock(&lapic_nmi_owner_lock); + if (old_owner & LAPIC_NMI_RESERVED) + return -EBUSY; + if (old_owner & LAPIC_NMI_WATCHDOG) + disable_lapic_nmi_watchdog(); + return 0; +} + +void release_lapic_nmi(void) +{ + unsigned int new_owner; + + spin_lock(&lapic_nmi_owner_lock); + new_owner = lapic_nmi_owner & ~LAPIC_NMI_RESERVED; + lapic_nmi_owner = new_owner; + spin_unlock(&lapic_nmi_owner_lock); + if (new_owner & LAPIC_NMI_WATCHDOG) + enable_lapic_nmi_watchdog(); +} + +#define __pminit __init /* * Activate the NMI watchdog via the local APIC. @@ -122,8 +211,19 @@ static void __pminit clear_msr_range(unsigned int base, unsigned int n) { unsigned int i; - for ( i = 0; i < n; i++ ) + + for (i = 0; i < n; i++) wrmsr(base+i, 0, 0); +} + +static inline void write_watchdog_counter(const char *descr) +{ + u64 count = (u64)cpu_khz * 1000; + + do_div(count, nmi_hz); + if(descr) + Dprintk("setting %s to -0x%08Lx\n", descr, count); + wrmsrl(nmi_perfctr_msr, 0 - count); } static void __pminit setup_k7_watchdog(void) @@ -141,8 +241,7 @@ | K7_NMI_EVENT; wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); - Dprintk("setting K7_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); - wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1); + write_watchdog_counter("K7_PERFCTR0"); apic_write(APIC_LVTPC, APIC_DM_NMI); evntsel |= K7_EVNTSEL_ENABLE; wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); @@ -163,8 +262,7 @@ | P6_NMI_EVENT; wrmsr(MSR_P6_EVNTSEL0, evntsel, 0); - Dprintk("setting P6_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); - wrmsr(MSR_P6_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0); + write_watchdog_counter("P6_PERFCTR0"); apic_write(APIC_LVTPC, APIC_DM_NMI); evntsel |= P6_EVNTSEL0_ENABLE; wrmsr(MSR_P6_EVNTSEL0, evntsel, 0); @@ -187,7 +285,13 @@ clear_msr_range(0x3F1, 2); /* MSR 0x3F0 seems to have a default value of 0xFC00, but current docs doesn't fully define it, so leave it alone for now. */ - clear_msr_range(0x3A0, 31); + if (boot_cpu_data.x86_model >= 0x3) { + /* MSR_P4_IQ_ESCR0/1 (0x3ba/0x3bb) removed */ + clear_msr_range(0x3A0, 26); + clear_msr_range(0x3BC, 3); + } else { + clear_msr_range(0x3A0, 31); + } clear_msr_range(0x3C0, 6); clear_msr_range(0x3C8, 6); clear_msr_range(0x3E0, 2); @@ -196,11 +300,9 @@ wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0); wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0); - Dprintk("setting P4_IQ_PERFCTR0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000)); - wrmsr(MSR_P4_IQ_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1); + write_watchdog_counter("P4_IQ_COUNTER0"); apic_write(APIC_LVTPC, APIC_DM_NMI); wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0); - return 1; } @@ -220,9 +322,15 @@ case X86_VENDOR_INTEL: switch (boot_cpu_data.x86) { case 6: + if (boot_cpu_data.x86_model > 0xd) + return; + setup_p6_watchdog(); break; case 15: + if (boot_cpu_data.x86_model > 0x4) + return; + if (!setup_p4_watchdog()) return; break; @@ -234,11 +342,11 @@ return; } + lapic_nmi_owner = LAPIC_NMI_WATCHDOG; + nmi_active = 1; + init_ac_timer(&nmi_timer[cpu], nmi_timer_fn, NULL, cpu); - - nmi_pm_init(); -} - +} static unsigned int last_irq_sums [NR_CPUS], @@ -329,6 +437,6 @@ */ apic_write(APIC_LVTPC, APIC_DM_NMI); } - wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1); - } -} + write_watchdog_counter(NULL); + } +} diff -r 06b80b837c92 -r db500b8cb79a xen/arch/x86/traps.c --- a/xen/arch/x86/traps.c Tue Dec 6 16:40:50 2005 +++ b/xen/arch/x86/traps.c Tue Dec 6 16:48:57 2005 @@ -54,6 +54,7 @@ #include <asm/debugger.h> #include <asm/msr.h> #include <asm/x86_emulate.h> +#include <asm/nmi.h> /* * opt_nmi: one of 'ignore', 'dom0', or 'fatal'. @@ -1131,10 +1132,8 @@ printk("Do you have a strange power saving mode enabled?\n"); } -asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason) -{ - ++nmi_count(smp_processor_id()); - +static void default_do_nmi(struct cpu_user_regs *regs, unsigned long reason) +{ if ( nmi_watchdog ) nmi_watchdog_tick(regs); @@ -1144,6 +1143,33 @@ io_check_error(regs); else if ( !nmi_watchdog ) unknown_nmi_error((unsigned char)(reason&0xff)); +} + +static int dummy_nmi_callback(struct cpu_user_regs *regs, int cpu) +{ + return 0; +} + +static nmi_callback_t nmi_callback = dummy_nmi_callback; + +asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason) +{ + unsigned int cpu = smp_processor_id(); + + ++nmi_count(cpu); + + if ( !nmi_callback(regs, cpu) ) + default_do_nmi(regs, reason); +} + +void set_nmi_callback(nmi_callback_t callback) +{ + nmi_callback = callback; +} + +void unset_nmi_callback(void) +{ + nmi_callback = dummy_nmi_callback; } asmlinkage int math_state_restore(struct cpu_user_regs *regs) diff -r 06b80b837c92 -r db500b8cb79a xen/include/asm-x86/msr.h --- a/xen/include/asm-x86/msr.h Tue Dec 6 16:40:50 2005 +++ b/xen/include/asm-x86/msr.h Tue Dec 6 16:48:57 2005 @@ -1,5 +1,7 @@ #ifndef __ASM_MSR_H #define __ASM_MSR_H + +#ifndef __ASSEMBLY__ #define rdmsr(msr,val1,val2) \ __asm__ __volatile__("rdmsr" \ @@ -18,7 +20,13 @@ : /* no outputs */ \ : "c" (msr), "a" (val1), "d" (val2)) -#define wrmsrl(msr,val) wrmsr(msr,(__u32)((__u64)(val)),((__u64)(val))>>32) +static inline void wrmsrl(unsigned int msr, __u64 val) +{ + __u32 lo, hi; + lo = (__u32)val; + hi = (__u32)(val >> 32); + wrmsr(msr, lo, hi); +} #define rdmsr_user(msr,val1,val2) ({\ int _rc; \ @@ -73,6 +81,8 @@ __asm__ __volatile__("rdpmc" \ : "=a" (low), "=d" (high) \ : "c" (counter)) + +#endif /* !__ASSEMBLY__ */ /* symbolic names for some interesting MSRs */ /* Intel defined MSRs. */ diff -r 06b80b837c92 -r db500b8cb79a xen/include/asm-x86/nmi.h --- /dev/null Tue Dec 6 16:40:50 2005 +++ b/xen/include/asm-x86/nmi.h Tue Dec 6 16:48:57 2005 @@ -0,0 +1,24 @@ + +#ifndef ASM_NMI_H +#define ASM_NMI_H + +struct cpu_user_regs; + +typedef int (*nmi_callback_t)(struct cpu_user_regs *regs, int cpu); + +/** + * set_nmi_callback + * + * Set a handler for an NMI. Only one handler may be + * set. Return 1 if the NMI was handled. + */ +void set_nmi_callback(nmi_callback_t callback); + +/** + * unset_nmi_callback + * + * Remove the handler previously set. + */ +void unset_nmi_callback(void); + +#endif /* ASM_NMI_H */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |