ia64/xen-unstable

changeset 7390:f9b300fab36e

This should fix time stopped / going slow problems that
various users have been seeing.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Fri Oct 14 18:27:25 2005 +0100 (2005-10-14)
parents d48bc069122c
children 06ce728dcede
files xen/arch/x86/time.c
line diff
     1.1 --- a/xen/arch/x86/time.c	Fri Oct 14 16:01:11 2005 +0100
     1.2 +++ b/xen/arch/x86/time.c	Fri Oct 14 18:27:25 2005 +0100
     1.3 @@ -61,7 +61,10 @@ struct cpu_time {
     1.4  
     1.5  static struct cpu_time cpu_time[NR_CPUS];
     1.6  
     1.7 -/* Protected by platform_timer_lock. */
     1.8 +/*
     1.9 + * Protected by platform_timer_lock, which must be acquired with interrupts
    1.10 + * disabled because pit_overflow() is called from PIT ch0 interrupt context.
    1.11 + */
    1.12  static s_time_t stime_platform_stamp;
    1.13  static u64 platform_timer_stamp;
    1.14  static struct time_scale platform_timer_scale;
    1.15 @@ -69,6 +72,14 @@ static spinlock_t platform_timer_lock = 
    1.16  static u64 (*read_platform_count)(void);
    1.17  
    1.18  /*
    1.19 + * Folding 16-bit PIT into 64-bit software counter is a really critical
    1.20 + * operation! We therefore do it directly in PIT ch0 interrupt handler,
    1.21 + * based on this flag.
    1.22 + */
    1.23 +static int using_pit;
    1.24 +static void pit_overflow(void);
    1.25 +
    1.26 +/*
    1.27   * 32-bit division of integer dividend and integer divisor yielding
    1.28   * 32-bit fractional quotient.
    1.29   */
    1.30 @@ -135,14 +146,16 @@ static inline u64 scale_delta(u64 delta,
    1.31  
    1.32  void timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
    1.33  {
    1.34 +    ASSERT(local_irq_is_enabled());
    1.35 +
    1.36      if ( timer_ack ) 
    1.37      {
    1.38          extern spinlock_t i8259A_lock;
    1.39 -        spin_lock(&i8259A_lock);
    1.40 +        spin_lock_irq(&i8259A_lock);
    1.41          outb(0x0c, 0x20);
    1.42          /* Ack the IRQ; AEOI will end it automatically. */
    1.43          inb(0x20);
    1.44 -        spin_unlock(&i8259A_lock);
    1.45 +        spin_unlock_irq(&i8259A_lock);
    1.46      }
    1.47      
    1.48      /* Update jiffies counter. */
    1.49 @@ -151,6 +164,9 @@ void timer_interrupt(int irq, void *dev_
    1.50      /* Rough hack to allow accurate timers to sort-of-work with no APIC. */
    1.51      if ( !cpu_has_apic )
    1.52          raise_softirq(AC_TIMER_SOFTIRQ);
    1.53 +
    1.54 +    if ( using_pit )
    1.55 +        pit_overflow();
    1.56  }
    1.57  
    1.58  static struct irqaction irq0 = { timer_interrupt, "timer", NULL};
    1.59 @@ -280,7 +296,6 @@ static char *freq_string(u64 freq)
    1.60  /* Protected by platform_timer_lock. */
    1.61  static u64 pit_counter64;
    1.62  static u16 pit_stamp;
    1.63 -static struct ac_timer pit_overflow_timer;
    1.64  
    1.65  static u16 pit_read_counter(void)
    1.66  {
    1.67 @@ -292,17 +307,15 @@ static u16 pit_read_counter(void)
    1.68      return count;
    1.69  }
    1.70  
    1.71 -static void pit_overflow(void *unused)
    1.72 +static void pit_overflow(void)
    1.73  {
    1.74      u16 counter;
    1.75  
    1.76 -    spin_lock(&platform_timer_lock);
    1.77 +    spin_lock_irq(&platform_timer_lock);
    1.78      counter = pit_read_counter();
    1.79      pit_counter64 += (u16)(pit_stamp - counter);
    1.80      pit_stamp = counter;
    1.81 -    spin_unlock(&platform_timer_lock);
    1.82 -
    1.83 -    set_ac_timer(&pit_overflow_timer, NOW() + MILLISECS(20));
    1.84 +    spin_unlock_irq(&platform_timer_lock);
    1.85  }
    1.86  
    1.87  static u64 read_pit_count(void)
    1.88 @@ -314,12 +327,12 @@ static int init_pit(void)
    1.89  {
    1.90      read_platform_count = read_pit_count;
    1.91  
    1.92 -    init_ac_timer(&pit_overflow_timer, pit_overflow, NULL, 0);
    1.93 -    pit_overflow(NULL);
    1.94 +    pit_overflow();
    1.95      platform_timer_stamp = pit_counter64;
    1.96      set_time_scale(&platform_timer_scale, CLOCK_TICK_RATE);
    1.97  
    1.98      printk("Platform timer is %s PIT\n", freq_string(CLOCK_TICK_RATE));
    1.99 +    using_pit = 1;
   1.100  
   1.101      return 1;
   1.102  }
   1.103 @@ -337,11 +350,11 @@ static void hpet_overflow(void *unused)
   1.104  {
   1.105      u32 counter;
   1.106  
   1.107 -    spin_lock(&platform_timer_lock);
   1.108 +    spin_lock_irq(&platform_timer_lock);
   1.109      counter = hpet_read32(HPET_COUNTER);
   1.110      hpet_counter64 += (u32)(counter - hpet_stamp);
   1.111      hpet_stamp = counter;
   1.112 -    spin_unlock(&platform_timer_lock);
   1.113 +    spin_unlock_irq(&platform_timer_lock);
   1.114  
   1.115      set_ac_timer(&hpet_overflow_timer, NOW() + hpet_overflow_period);
   1.116  }
   1.117 @@ -455,11 +468,11 @@ static void cyclone_overflow(void *unuse
   1.118  {
   1.119      u32 counter;
   1.120  
   1.121 -    spin_lock(&platform_timer_lock);
   1.122 +    spin_lock_irq(&platform_timer_lock);
   1.123      counter = *cyclone_timer;
   1.124      cyclone_counter64 += (u32)(counter - cyclone_stamp);
   1.125      cyclone_stamp = counter;
   1.126 -    spin_unlock(&platform_timer_lock);
   1.127 +    spin_unlock_irq(&platform_timer_lock);
   1.128  
   1.129      set_ac_timer(&cyclone_overflow_timer, NOW() + MILLISECS(20000));
   1.130  }
   1.131 @@ -526,10 +539,10 @@ static s_time_t read_platform_stime(void
   1.132      u64 counter;
   1.133      s_time_t stime;
   1.134  
   1.135 -    spin_lock(&platform_timer_lock);
   1.136 +    spin_lock_irq(&platform_timer_lock);
   1.137      counter = read_platform_count();
   1.138      stime   = __read_platform_stime(counter);
   1.139 -    spin_unlock(&platform_timer_lock);
   1.140 +    spin_unlock_irq(&platform_timer_lock);
   1.141  
   1.142      return stime;
   1.143  }
   1.144 @@ -539,12 +552,12 @@ static void platform_time_calibration(vo
   1.145      u64 counter;
   1.146      s_time_t stamp;
   1.147  
   1.148 -    spin_lock(&platform_timer_lock);
   1.149 +    spin_lock_irq(&platform_timer_lock);
   1.150      counter = read_platform_count();
   1.151      stamp   = __read_platform_stime(counter);
   1.152      stime_platform_stamp = stamp;
   1.153      platform_timer_stamp = counter;
   1.154 -    spin_unlock(&platform_timer_lock);
   1.155 +    spin_unlock_irq(&platform_timer_lock);
   1.156  }
   1.157  
   1.158  static void init_platform_timer(void)