ia64/xen-unstable

changeset 8255:db500b8cb79a

Pull nmi/traps changes from Linux 2.6.14.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Tue Dec 06 17:48:57 2005 +0100 (2005-12-06)
parents 06b80b837c92
children 0faff739723e
files xen/arch/x86/nmi.c xen/arch/x86/traps.c xen/include/asm-x86/msr.h xen/include/asm-x86/nmi.h
line diff
     1.1 --- a/xen/arch/x86/nmi.c	Tue Dec 06 16:40:50 2005 +0000
     1.2 +++ b/xen/arch/x86/nmi.c	Tue Dec 06 17:48:57 2005 +0100
     1.3 @@ -9,7 +9,8 @@
     1.4   *  Mikael Pettersson	: AMD K7 support for local APIC NMI watchdog.
     1.5   *  Mikael Pettersson	: Power Management for local APIC NMI watchdog.
     1.6   *  Mikael Pettersson	: Pentium 4 support for local APIC NMI watchdog.
     1.7 - *  Keir Fraser         : Pentium 4 Hyperthreading support
     1.8 + *  Pavel Machek and
     1.9 + *  Mikael Pettersson	: PM converted to driver model. Disable/enable API.
    1.10   */
    1.11  
    1.12  #include <xen/config.h>
    1.13 @@ -27,6 +28,7 @@
    1.14  #include <asm/msr.h>
    1.15  #include <asm/mpspec.h>
    1.16  #include <asm/debugger.h>
    1.17 +#include <asm/div64.h>
    1.18  
    1.19  unsigned int nmi_watchdog = NMI_NONE;
    1.20  static unsigned int nmi_hz = HZ;
    1.21 @@ -35,6 +37,28 @@ static unsigned int nmi_p4_cccr_val;
    1.22  static struct ac_timer nmi_timer[NR_CPUS];
    1.23  static unsigned int nmi_timer_ticks[NR_CPUS];
    1.24  
    1.25 +/*
    1.26 + * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
    1.27 + * - it may be reserved by some other driver, or not
    1.28 + * - when not reserved by some other driver, it may be used for
    1.29 + *   the NMI watchdog, or not
    1.30 + *
    1.31 + * This is maintained separately from nmi_active because the NMI
    1.32 + * watchdog may also be driven from the I/O APIC timer.
    1.33 + */
    1.34 +static DEFINE_SPINLOCK(lapic_nmi_owner_lock);
    1.35 +static unsigned int lapic_nmi_owner;
    1.36 +#define LAPIC_NMI_WATCHDOG	(1<<0)
    1.37 +#define LAPIC_NMI_RESERVED	(1<<1)
    1.38 +
    1.39 +/* nmi_active:
    1.40 + * +1: the lapic NMI watchdog is active, but can be disabled
    1.41 + *  0: the lapic NMI watchdog has not been set up, and cannot
    1.42 + *     be enabled
    1.43 + * -1: the lapic NMI watchdog is disabled, but can be enabled
    1.44 + */
    1.45 +int nmi_active;
    1.46 +
    1.47  #define K7_EVNTSEL_ENABLE	(1 << 22)
    1.48  #define K7_EVNTSEL_INT		(1 << 20)
    1.49  #define K7_EVNTSEL_OS		(1 << 17)
    1.50 @@ -111,8 +135,73 @@ static void nmi_timer_fn(void *unused)
    1.51      set_ac_timer(&nmi_timer[cpu], NOW() + MILLISECS(1000));
    1.52  }
    1.53  
    1.54 -static inline void nmi_pm_init(void) { }
    1.55 -#define __pminit	__init
    1.56 +static void disable_lapic_nmi_watchdog(void)
    1.57 +{
    1.58 +    if (nmi_active <= 0)
    1.59 +        return;
    1.60 +    switch (boot_cpu_data.x86_vendor) {
    1.61 +    case X86_VENDOR_AMD:
    1.62 +        wrmsr(MSR_K7_EVNTSEL0, 0, 0);
    1.63 +        break;
    1.64 +    case X86_VENDOR_INTEL:
    1.65 +        switch (boot_cpu_data.x86) {
    1.66 +        case 6:
    1.67 +            if (boot_cpu_data.x86_model > 0xd)
    1.68 +                break;
    1.69 +
    1.70 +            wrmsr(MSR_P6_EVNTSEL0, 0, 0);
    1.71 +            break;
    1.72 +        case 15:
    1.73 +            if (boot_cpu_data.x86_model > 0x4)
    1.74 +                break;
    1.75 +
    1.76 +            wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
    1.77 +            wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
    1.78 +            break;
    1.79 +        }
    1.80 +        break;
    1.81 +    }
    1.82 +    nmi_active = -1;
    1.83 +    /* tell do_nmi() and others that we're not active any more */
    1.84 +    nmi_watchdog = 0;
    1.85 +}
    1.86 +
    1.87 +static void enable_lapic_nmi_watchdog(void)
    1.88 +{
    1.89 +    if (nmi_active < 0) {
    1.90 +        nmi_watchdog = NMI_LOCAL_APIC;
    1.91 +        setup_apic_nmi_watchdog();
    1.92 +    }
    1.93 +}
    1.94 +
    1.95 +int reserve_lapic_nmi(void)
    1.96 +{
    1.97 +    unsigned int old_owner;
    1.98 +
    1.99 +    spin_lock(&lapic_nmi_owner_lock);
   1.100 +    old_owner = lapic_nmi_owner;
   1.101 +    lapic_nmi_owner |= LAPIC_NMI_RESERVED;
   1.102 +    spin_unlock(&lapic_nmi_owner_lock);
   1.103 +    if (old_owner & LAPIC_NMI_RESERVED)
   1.104 +        return -EBUSY;
   1.105 +    if (old_owner & LAPIC_NMI_WATCHDOG)
   1.106 +        disable_lapic_nmi_watchdog();
   1.107 +    return 0;
   1.108 +}
   1.109 +
   1.110 +void release_lapic_nmi(void)
   1.111 +{
   1.112 +    unsigned int new_owner;
   1.113 +
   1.114 +    spin_lock(&lapic_nmi_owner_lock);
   1.115 +    new_owner = lapic_nmi_owner & ~LAPIC_NMI_RESERVED;
   1.116 +    lapic_nmi_owner = new_owner;
   1.117 +    spin_unlock(&lapic_nmi_owner_lock);
   1.118 +    if (new_owner & LAPIC_NMI_WATCHDOG)
   1.119 +        enable_lapic_nmi_watchdog();
   1.120 +}
   1.121 +
   1.122 +#define __pminit __init
   1.123  
   1.124  /*
   1.125   * Activate the NMI watchdog via the local APIC.
   1.126 @@ -122,10 +211,21 @@ static inline void nmi_pm_init(void) { }
   1.127  static void __pminit clear_msr_range(unsigned int base, unsigned int n)
   1.128  {
   1.129      unsigned int i;
   1.130 -    for ( i = 0; i < n; i++ )
   1.131 +
   1.132 +    for (i = 0; i < n; i++)
   1.133          wrmsr(base+i, 0, 0);
   1.134  }
   1.135  
   1.136 +static inline void write_watchdog_counter(const char *descr)
   1.137 +{
   1.138 +    u64 count = (u64)cpu_khz * 1000;
   1.139 +
   1.140 +    do_div(count, nmi_hz);
   1.141 +    if(descr)
   1.142 +        Dprintk("setting %s to -0x%08Lx\n", descr, count);
   1.143 +    wrmsrl(nmi_perfctr_msr, 0 - count);
   1.144 +}
   1.145 +
   1.146  static void __pminit setup_k7_watchdog(void)
   1.147  {
   1.148      unsigned int evntsel;
   1.149 @@ -141,8 +241,7 @@ static void __pminit setup_k7_watchdog(v
   1.150          | K7_NMI_EVENT;
   1.151  
   1.152      wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
   1.153 -    Dprintk("setting K7_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
   1.154 -    wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1);
   1.155 +    write_watchdog_counter("K7_PERFCTR0");
   1.156      apic_write(APIC_LVTPC, APIC_DM_NMI);
   1.157      evntsel |= K7_EVNTSEL_ENABLE;
   1.158      wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
   1.159 @@ -163,8 +262,7 @@ static void __pminit setup_p6_watchdog(v
   1.160          | P6_NMI_EVENT;
   1.161  
   1.162      wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
   1.163 -    Dprintk("setting P6_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
   1.164 -    wrmsr(MSR_P6_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0);
   1.165 +    write_watchdog_counter("P6_PERFCTR0");
   1.166      apic_write(APIC_LVTPC, APIC_DM_NMI);
   1.167      evntsel |= P6_EVNTSEL0_ENABLE;
   1.168      wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
   1.169 @@ -187,7 +285,13 @@ static int __pminit setup_p4_watchdog(vo
   1.170          clear_msr_range(0x3F1, 2);
   1.171      /* MSR 0x3F0 seems to have a default value of 0xFC00, but current
   1.172         docs doesn't fully define it, so leave it alone for now. */
   1.173 -    clear_msr_range(0x3A0, 31);
   1.174 +    if (boot_cpu_data.x86_model >= 0x3) {
   1.175 +        /* MSR_P4_IQ_ESCR0/1 (0x3ba/0x3bb) removed */
   1.176 +        clear_msr_range(0x3A0, 26);
   1.177 +        clear_msr_range(0x3BC, 3);
   1.178 +    } else {
   1.179 +        clear_msr_range(0x3A0, 31);
   1.180 +    }
   1.181      clear_msr_range(0x3C0, 6);
   1.182      clear_msr_range(0x3C8, 6);
   1.183      clear_msr_range(0x3E0, 2);
   1.184 @@ -196,11 +300,9 @@ static int __pminit setup_p4_watchdog(vo
   1.185          
   1.186      wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
   1.187      wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
   1.188 -    Dprintk("setting P4_IQ_PERFCTR0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000));
   1.189 -    wrmsr(MSR_P4_IQ_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1);
   1.190 +    write_watchdog_counter("P4_IQ_COUNTER0");
   1.191      apic_write(APIC_LVTPC, APIC_DM_NMI);
   1.192      wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
   1.193 -
   1.194      return 1;
   1.195  }
   1.196  
   1.197 @@ -220,9 +322,15 @@ void __pminit setup_apic_nmi_watchdog(vo
   1.198      case X86_VENDOR_INTEL:
   1.199          switch (boot_cpu_data.x86) {
   1.200          case 6:
   1.201 +            if (boot_cpu_data.x86_model > 0xd)
   1.202 +                return;
   1.203 +
   1.204              setup_p6_watchdog();
   1.205              break;
   1.206          case 15:
   1.207 +            if (boot_cpu_data.x86_model > 0x4)
   1.208 +                return;
   1.209 +
   1.210              if (!setup_p4_watchdog())
   1.211                  return;
   1.212              break;
   1.213 @@ -234,12 +342,12 @@ void __pminit setup_apic_nmi_watchdog(vo
   1.214          return;
   1.215      }
   1.216  
   1.217 -    init_ac_timer(&nmi_timer[cpu], nmi_timer_fn, NULL, cpu);
   1.218 +    lapic_nmi_owner = LAPIC_NMI_WATCHDOG;
   1.219 +    nmi_active = 1;
   1.220  
   1.221 -    nmi_pm_init();
   1.222 +    init_ac_timer(&nmi_timer[cpu], nmi_timer_fn, NULL, cpu);
   1.223  }
   1.224  
   1.225 -
   1.226  static unsigned int
   1.227  last_irq_sums [NR_CPUS],
   1.228      alert_counter [NR_CPUS];
   1.229 @@ -329,6 +437,6 @@ void nmi_watchdog_tick(struct cpu_user_r
   1.230               */
   1.231              apic_write(APIC_LVTPC, APIC_DM_NMI);
   1.232          }
   1.233 -        wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
   1.234 +        write_watchdog_counter(NULL);
   1.235      }
   1.236  }
     2.1 --- a/xen/arch/x86/traps.c	Tue Dec 06 16:40:50 2005 +0000
     2.2 +++ b/xen/arch/x86/traps.c	Tue Dec 06 17:48:57 2005 +0100
     2.3 @@ -54,6 +54,7 @@
     2.4  #include <asm/debugger.h>
     2.5  #include <asm/msr.h>
     2.6  #include <asm/x86_emulate.h>
     2.7 +#include <asm/nmi.h>
     2.8  
     2.9  /*
    2.10   * opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
    2.11 @@ -1131,10 +1132,8 @@ static void unknown_nmi_error(unsigned c
    2.12      printk("Do you have a strange power saving mode enabled?\n");
    2.13  }
    2.14  
    2.15 -asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason)
    2.16 +static void default_do_nmi(struct cpu_user_regs *regs, unsigned long reason)
    2.17  {
    2.18 -    ++nmi_count(smp_processor_id());
    2.19 -
    2.20      if ( nmi_watchdog )
    2.21          nmi_watchdog_tick(regs);
    2.22  
    2.23 @@ -1146,6 +1145,33 @@ asmlinkage void do_nmi(struct cpu_user_r
    2.24          unknown_nmi_error((unsigned char)(reason&0xff));
    2.25  }
    2.26  
    2.27 +static int dummy_nmi_callback(struct cpu_user_regs *regs, int cpu)
    2.28 +{
    2.29 +	return 0;
    2.30 +}
    2.31 + 
    2.32 +static nmi_callback_t nmi_callback = dummy_nmi_callback;
    2.33 + 
    2.34 +asmlinkage void do_nmi(struct cpu_user_regs *regs, unsigned long reason)
    2.35 +{
    2.36 +    unsigned int cpu = smp_processor_id();
    2.37 +
    2.38 +    ++nmi_count(cpu);
    2.39 +
    2.40 +	if ( !nmi_callback(regs, cpu) )
    2.41 +		default_do_nmi(regs, reason);
    2.42 +}
    2.43 +
    2.44 +void set_nmi_callback(nmi_callback_t callback)
    2.45 +{
    2.46 +    nmi_callback = callback;
    2.47 +}
    2.48 +
    2.49 +void unset_nmi_callback(void)
    2.50 +{
    2.51 +	nmi_callback = dummy_nmi_callback;
    2.52 +}
    2.53 +
    2.54  asmlinkage int math_state_restore(struct cpu_user_regs *regs)
    2.55  {
    2.56      struct trap_bounce *tb;
     3.1 --- a/xen/include/asm-x86/msr.h	Tue Dec 06 16:40:50 2005 +0000
     3.2 +++ b/xen/include/asm-x86/msr.h	Tue Dec 06 17:48:57 2005 +0100
     3.3 @@ -1,6 +1,8 @@
     3.4  #ifndef __ASM_MSR_H
     3.5  #define __ASM_MSR_H
     3.6  
     3.7 +#ifndef __ASSEMBLY__
     3.8 +
     3.9  #define rdmsr(msr,val1,val2) \
    3.10       __asm__ __volatile__("rdmsr" \
    3.11  			  : "=a" (val1), "=d" (val2) \
    3.12 @@ -18,7 +20,13 @@
    3.13  			  : /* no outputs */ \
    3.14  			  : "c" (msr), "a" (val1), "d" (val2))
    3.15  
    3.16 -#define wrmsrl(msr,val) wrmsr(msr,(__u32)((__u64)(val)),((__u64)(val))>>32) 
    3.17 +static inline void wrmsrl(unsigned int msr, __u64 val)
    3.18 +{
    3.19 +        __u32 lo, hi;
    3.20 +        lo = (__u32)val;
    3.21 +        hi = (__u32)(val >> 32);
    3.22 +        wrmsr(msr, lo, hi);
    3.23 +}
    3.24  
    3.25  #define rdmsr_user(msr,val1,val2) ({\
    3.26      int _rc; \
    3.27 @@ -74,6 +82,8 @@
    3.28  			  : "=a" (low), "=d" (high) \
    3.29  			  : "c" (counter))
    3.30  
    3.31 +#endif /* !__ASSEMBLY__ */
    3.32 +
    3.33  /* symbolic names for some interesting MSRs */
    3.34  /* Intel defined MSRs. */
    3.35  #define MSR_IA32_P5_MC_ADDR		0
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/xen/include/asm-x86/nmi.h	Tue Dec 06 17:48:57 2005 +0100
     4.3 @@ -0,0 +1,24 @@
     4.4 +
     4.5 +#ifndef ASM_NMI_H
     4.6 +#define ASM_NMI_H
     4.7 +
     4.8 +struct cpu_user_regs;
     4.9 + 
    4.10 +typedef int (*nmi_callback_t)(struct cpu_user_regs *regs, int cpu);
    4.11 + 
    4.12 +/** 
    4.13 + * set_nmi_callback
    4.14 + *
    4.15 + * Set a handler for an NMI. Only one handler may be
    4.16 + * set. Return 1 if the NMI was handled.
    4.17 + */
    4.18 +void set_nmi_callback(nmi_callback_t callback);
    4.19 + 
    4.20 +/** 
    4.21 + * unset_nmi_callback
    4.22 + *
    4.23 + * Remove the handler previously set.
    4.24 + */
    4.25 +void unset_nmi_callback(void);
    4.26 + 
    4.27 +#endif /* ASM_NMI_H */