ia64/xen-unstable

changeset 8594:026e5ef0aa3c

Fix up the way we initialise and set the NMI heartbeat
timers. Also, compund updates to APIC ICR and ICR2 registers
must be done with interrupts disabled to ensure local
atomicity.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Fri Jan 13 16:09:45 2006 +0100 (2006-01-13)
parents 903420e4d449
children 0c5980d0bf20
files xen/arch/x86/apic.c xen/arch/x86/nmi.c xen/arch/x86/setup.c
line diff
     1.1 --- a/xen/arch/x86/apic.c	Fri Jan 13 14:59:40 2006 +0000
     1.2 +++ b/xen/arch/x86/apic.c	Fri Jan 13 16:09:45 2006 +0100
     1.3 @@ -451,7 +451,8 @@ void __init setup_local_APIC (void)
     1.4              printk("No ESR for 82489DX.\n");
     1.5      }
     1.6  
     1.7 -    setup_apic_nmi_watchdog();
     1.8 +    if (nmi_watchdog == NMI_LOCAL_APIC)
     1.9 +        setup_apic_nmi_watchdog();
    1.10  }
    1.11  
    1.12  /*
     2.1 --- a/xen/arch/x86/nmi.c	Fri Jan 13 14:59:40 2006 +0000
     2.2 +++ b/xen/arch/x86/nmi.c	Fri Jan 13 16:09:45 2006 +0100
     2.3 @@ -33,10 +33,6 @@
     2.4  #include <asm/apic.h>
     2.5  
     2.6  unsigned int nmi_watchdog = NMI_NONE;
     2.7 -static spinlock_t   watchdog_lock = SPIN_LOCK_UNLOCKED;
     2.8 -static unsigned int watchdog_disable_count = 1;
     2.9 -static unsigned int watchdog_on;
    2.10 -
    2.11  static unsigned int nmi_hz = HZ;
    2.12  static unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
    2.13  static unsigned int nmi_p4_cccr_val;
    2.14 @@ -314,18 +310,8 @@ static int __pminit setup_p4_watchdog(vo
    2.15  
    2.16  void __pminit setup_apic_nmi_watchdog(void)
    2.17  {
    2.18 -    int cpu = smp_processor_id();
    2.19 -
    2.20 -    if ( nmi_active < 0 )
    2.21 -	return;
    2.22 -
    2.23 -    if ( !nmi_watchdog )
    2.24 -    {
    2.25 -	/* Force the watchdog to always be disabled. */
    2.26 -	watchdog_disable_count++;
    2.27 -	nmi_active = -1;
    2.28 -	return;
    2.29 -    }
    2.30 +    if (!nmi_watchdog)
    2.31 +        return;
    2.32  
    2.33      switch (boot_cpu_data.x86_vendor) {
    2.34      case X86_VENDOR_AMD:
    2.35 @@ -358,45 +344,37 @@ void __pminit setup_apic_nmi_watchdog(vo
    2.36  
    2.37      lapic_nmi_owner = LAPIC_NMI_WATCHDOG;
    2.38      nmi_active = 1;
    2.39 -
    2.40 -    init_timer(&nmi_timer[cpu], nmi_timer_fn, NULL, cpu);
    2.41  }
    2.42  
    2.43  static unsigned int
    2.44  last_irq_sums [NR_CPUS],
    2.45      alert_counter [NR_CPUS];
    2.46  
    2.47 +static atomic_t watchdog_disable_count = ATOMIC_INIT(1);
    2.48 +
    2.49  void watchdog_disable(void)
    2.50  {
    2.51 -    unsigned long flags;
    2.52 -
    2.53 -    spin_lock_irqsave(&watchdog_lock, flags);
    2.54 -
    2.55 -    if ( watchdog_disable_count++ == 0 )
    2.56 -        watchdog_on = 0;
    2.57 -
    2.58 -    spin_unlock_irqrestore(&watchdog_lock, flags);
    2.59 +    atomic_inc(&watchdog_disable_count);
    2.60  }
    2.61  
    2.62  void watchdog_enable(void)
    2.63  {
    2.64 -    unsigned int  cpu;
    2.65 -    unsigned long flags;
    2.66 +    static unsigned long heartbeat_initialised;
    2.67 +    unsigned int cpu;
    2.68  
    2.69 -    spin_lock_irqsave(&watchdog_lock, flags);
    2.70 +    if ( !atomic_dec_and_test(&watchdog_disable_count) ||
    2.71 +         test_and_set_bit(0, &heartbeat_initialised) )
    2.72 +        return;
    2.73  
    2.74 -    if ( --watchdog_disable_count == 0 )
    2.75 +    /*
    2.76 +     * Activate periodic heartbeats. We cannot do this earlier during 
    2.77 +     * setup because the timer infrastructure is not available.
    2.78 +     */
    2.79 +    for_each_online_cpu ( cpu )
    2.80      {
    2.81 -        watchdog_on = 1;
    2.82 -        /*
    2.83 -         * Ensure periodic heartbeats are active. We cannot do this earlier
    2.84 -         * during setup because the timer infrastructure is not available. 
    2.85 -         */
    2.86 -        for_each_online_cpu ( cpu )
    2.87 -            set_timer(&nmi_timer[cpu], NOW());
    2.88 +        init_timer(&nmi_timer[cpu], nmi_timer_fn, NULL, cpu);
    2.89 +        set_timer(&nmi_timer[cpu], NOW());
    2.90      }
    2.91 -
    2.92 -    spin_unlock_irqrestore(&watchdog_lock, flags);
    2.93  }
    2.94  
    2.95  void nmi_watchdog_tick(struct cpu_user_regs * regs)
    2.96 @@ -405,7 +383,7 @@ void nmi_watchdog_tick(struct cpu_user_r
    2.97  
    2.98      sum = nmi_timer_ticks[cpu];
    2.99  
   2.100 -    if ( (last_irq_sums[cpu] == sum) && watchdog_on )
   2.101 +    if ( (last_irq_sums[cpu] == sum) && !atomic_read(&watchdog_disable_count) )
   2.102      {
   2.103          /*
   2.104           * Ayiee, looks like this CPU is stuck ... wait a few IRQs (5 seconds) 
   2.105 @@ -457,14 +435,17 @@ void nmi_watchdog_tick(struct cpu_user_r
   2.106   * 8-3 and 8-4 in IA32 Reference Manual Volume 3. We send the IPI to
   2.107   * our own APIC ID explicitly which is valid.
   2.108   */
   2.109 -static void do_nmi_trigger(unsigned char key) {
   2.110 +static void do_nmi_trigger(unsigned char key)
   2.111 +{
   2.112      u32 id = apic_read(APIC_ID);
   2.113  
   2.114 -    printk("triggering NMI on APIC ID %x\n", id);
   2.115 +    printk("Triggering NMI on APIC ID %x\n", id);
   2.116  
   2.117 +    local_irq_disable();
   2.118      apic_wait_icr_idle();
   2.119      apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(id));
   2.120      apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_INT_ASSERT);
   2.121 +    local_irq_enable();
   2.122  }
   2.123  
   2.124  static __init int register_nmi_trigger(void)
     3.1 --- a/xen/arch/x86/setup.c	Fri Jan 13 14:59:40 2006 +0000
     3.2 +++ b/xen/arch/x86/setup.c	Fri Jan 13 16:09:45 2006 +0100
     3.3 @@ -478,7 +478,8 @@ void __init __start_xen(multiboot_info_t
     3.4  
     3.5      schedulers_start();
     3.6  
     3.7 -    watchdog_enable();
     3.8 +    if ( opt_watchdog ) 
     3.9 +        watchdog_enable();
    3.10  
    3.11      shadow_mode_init();
    3.12