Pull nmi/traps changes from Linux 2.6.14.

Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
kaf24@firebug.cl.cam.ac.uk committed 2005-12-06 17:48:57 +01:00
1 parent b978d1410a
commit af50dd63cf
4 files changed
+188 -20

No files matched your search

+124 -16
View File
@@ -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;
@@ -35,6 +37,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)
#define K7_EVNTSEL_OS (1 << 17)
@@ -111,8 +135,73 @@ static void nmi_timer_fn(void *unused)
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,10 +211,21 @@ static inline void nmi_pm_init(void) { }
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)
{
unsigned int evntsel;
@@ -141,8 +241,7 @@ static void __pminit setup_k7_watchdog(void)
| 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 @@ static void __pminit setup_p6_watchdog(void)
| 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 @@ static int __pminit setup_p4_watchdog(void)
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 @@ static int __pminit setup_p4_watchdog(void)
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 @@ void __pminit setup_apic_nmi_watchdog(void)
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,12 +342,12 @@ void __pminit setup_apic_nmi_watchdog(void)
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],
alert_counter [NR_CPUS];
@@ -329,6 +437,6 @@ void nmi_watchdog_tick(struct cpu_user_regs * regs)
*/
apic_write(APIC_LVTPC, APIC_DM_NMI);
}
wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
write_watchdog_counter(NULL);
}
}
+29 -3
View File
@@ -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 @@ static void unknown_nmi_error(unsigned char reason)
printk("Do you have a strange power saving mode enabled?\n");
}
asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason)
static void default_do_nmi(struct cpu_user_regs *regs, unsigned long reason)
{
++nmi_count(smp_processor_id());
if ( nmi_watchdog )
nmi_watchdog_tick(regs);
@@ -1146,6 +1145,33 @@ asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason)
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)
{
struct trap_bounce *tb;
+11 -1
View File
@@ -1,6 +1,8 @@
#ifndef __ASM_MSR_H
#define __ASM_MSR_H
#ifndef __ASSEMBLY__
#define rdmsr(msr,val1,val2) \
__asm__ __volatile__("rdmsr" \
: "=a" (val1), "=d" (val2) \
@@ -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; \
@@ -74,6 +82,8 @@
: "=a" (low), "=d" (high) \
: "c" (counter))
#endif /* !__ASSEMBLY__ */
/* symbolic names for some interesting MSRs */
/* Intel defined MSRs. */
#define MSR_IA32_P5_MC_ADDR 0
+24
View File
@@ -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 */
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.