Convert lapic, pit and hpet based timers to clockevents.
This brings x86_64 in line with i386.  And it is needed
to enable dynticks.

Signed-off-by: Chris Wright <[EMAIL PROTECTED]>
Cc: Thomas Gleixner <[EMAIL PROTECTED]>
Cc: Ingo Molnar <[EMAIL PROTECTED]>
Cc: john stultz <[EMAIL PROTECTED]>
Cc: Andi Kleen <[EMAIL PROTECTED]>
---
 arch/x86_64/Kconfig       |    8 +
 arch/x86_64/kernel/apic.c |  123 ++++++++++++++++++++-------
 arch/x86_64/kernel/hpet.c |  168 +++++++++++++++++++++++++++++--------
 arch/x86_64/kernel/time.c |  204 ++++++++++++++++------------------------------
 include/asm-x86_64/hpet.h |    2 
 5 files changed, 307 insertions(+), 198 deletions(-)

--- linus-2.6.orig/arch/x86_64/kernel/time.c
+++ linus-2.6/arch/x86_64/kernel/time.c
@@ -42,10 +42,19 @@
 #include <linux/cpufreq.h>
 #include <linux/hpet.h>
 #include <asm/apic.h>
+#include <linux/clockchips.h>
+#include <asm/delay.h>
 #include <asm/hpet.h>
 
 extern void i8254_timer_resume(void);
 extern int using_apic_timer;
+extern struct clock_event_device pit_clockevent;
+/*
+ * HPET replaces the PIT, when enabled. So we need to know, which of
+ * the two timers is used
+ */
+struct clock_event_device *global_clock_event;
+
 
 static char *timename = NULL;
 
@@ -197,34 +206,7 @@ void notify_arch_cmos_timer(void)
 
 void main_timer_handler(void)
 {
-/*
- * Here we are in the timer irq handler. We have irqs locally disabled (so we
- * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
- * on the other CPU, so we need a lock. We also need to lock the vsyscall
- * variables, because both do_timer() and us change them -arca+vojtech
- */
-
-       write_seqlock(&xtime_lock);
-
-/*
- * Do the timer stuff.
- */
-
-       do_timer(1);
-#ifndef CONFIG_SMP
-       update_process_times(user_mode(get_irq_regs()));
-#endif
-
-/*
- * In the SMP case we use the local APIC timer interrupt to do the profiling,
- * except when we simulate SMP mode on a uniprocessor system, in that case we
- * have to call the local interrupt handler.
- */
-
-       if (!using_apic_timer)
-               smp_local_timer_interrupt();
-
-       write_sequnlock(&xtime_lock);
+       global_clock_event->event_handler(global_clock_event);
 }
 
 static irqreturn_t timer_interrupt(int irq, void *dev_id)
@@ -237,7 +219,7 @@ static irqreturn_t timer_interrupt(int i
        return IRQ_HANDLED;
 }
 
-static unsigned long get_cmos_time(void)
+unsigned long read_persistent_clock(void)
 {
        unsigned int year, mon, day, hour, min, sec;
        unsigned long flags;
@@ -321,38 +303,80 @@ static unsigned int __init pit_calibrate
 #define PIT_MODE 0x43
 #define PIT_CH0  0x40
 
-static void __init __pit_init(int val, u8 mode)
+static void init_pit_timer(enum clock_event_mode mode,
+                          struct clock_event_device *evt)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&i8253_lock, flags);
-       outb_p(mode, PIT_MODE);
-       outb_p(val & 0xff, PIT_CH0);    /* LSB */
-       outb_p(val >> 8, PIT_CH0);      /* MSB */
+
+       switch(mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               /* binary, mode 2, LSB/MSB, ch 0 */
+               outb_p(0x34, PIT_MODE);
+               udelay(10);
+               outb_p(LATCH & 0xff , PIT_CH0); /* LSB */
+               outb(LATCH >> 8 , PIT_CH0);     /* MSB */
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+               /* One shot setup */
+               outb_p(0x38, PIT_MODE);
+               udelay(10);
+               break;
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_UNUSED:
+               outb_p(0x30, PIT_MODE);
+               outb_p(0, PIT_CH0);     /* LSB */
+               outb_p(0, PIT_CH0);     /* MSB */
+               break;
+       }
        spin_unlock_irqrestore(&i8253_lock, flags);
 }
 
-void __init pit_init(void)
+static int pit_next_event(unsigned long delta, struct clock_event_device *evt)
 {
-       __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
+       unsigned long flags;
+
+       spin_lock_irqsave(&i8253_lock, flags);
+       outb_p(delta & 0xff , PIT_CH0); /* LSB */
+       outb(delta >> 8 , PIT_CH0);     /* MSB */
+       spin_unlock_irqrestore(&i8253_lock, flags);
+
+       return 0;
 }
 
-void __init pit_stop_interrupt(void)
+struct clock_event_device pit_clockevent = {
+       .name           = "pit",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_mode       = init_pit_timer,
+       .set_next_event = pit_next_event,
+       .shift          = 32,
+       .irq            = 0,
+};
+
+void __init stop_timer_interrupt(void)
 {
-       __pit_init(0, 0x30); /* mode 0 */
+       /* XXX this is bogus */
+       clockevents_set_mode(global_clock_event, CLOCK_EVT_MODE_SHUTDOWN);
+       printk(KERN_INFO "timer: %s interrupt stopped.\n", 
global_clock_event->name);
 }
 
-void __init stop_timer_interrupt(void)
+static void __init setup_pit_timer(void)
 {
-       char *name;
-       if (hpet_address) {
-               name = "HPET";
-               hpet_timer_stop_set_go(0);
-       } else {
-               name = "PIT";
-               pit_stop_interrupt();
-       }
-       printk(KERN_INFO "timer: %s interrupt stopped.\n", name);
+       /*
+        * Start pit with the boot cpu mask and make it global after the
+        * IO_APIC has been initialized.
+        */
+       pit_clockevent.cpumask = cpumask_of_cpu(0);
+
+       pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32);
+       pit_clockevent.max_delta_ns =
+               clockevent_delta2ns(0x7FFF, &pit_clockevent);
+       pit_clockevent.min_delta_ns =
+               clockevent_delta2ns(0xF, &pit_clockevent);
+       clockevents_register_device(&pit_clockevent);
+       global_clock_event = &pit_clockevent;
 }
 
 static struct irqaction irq0 = {
@@ -361,16 +385,8 @@ static struct irqaction irq0 = {
 
 void __init time_init(void)
 {
-       if (nohpet)
-               hpet_address = 0;
-       xtime.tv_sec = get_cmos_time();
-       xtime.tv_nsec = 0;
-
-       set_normalized_timespec(&wall_to_monotonic,
-                               -xtime.tv_sec, -xtime.tv_nsec);
-
-       if (hpet_arch_init())
-               hpet_address = 0;
+       if (!hpet_arch_init())
+               setup_pit_timer();
 
        if (hpet_use_timer) {
                /* set tick_nsec to use the proper rate for HPET */
@@ -378,7 +394,6 @@ void __init time_init(void)
                cpu_khz = hpet_calibrate_tsc();
                timename = "HPET";
        } else {
-               pit_init();
                cpu_khz = pit_calibrate_tsc();
                timename = "PIT";
        }
@@ -398,76 +413,3 @@ void __init time_init(void)
 
        setup_irq(0, &irq0);
 }
-
-
-static long clock_cmos_diff;
-static unsigned long sleep_start;
-
-/*
- * sysfs support for the timer.
- */
-
-static int timer_suspend(struct sys_device *dev, pm_message_t state)
-{
-       /*
-        * Estimate time zone so that set_time can update the clock
-        */
-       long cmos_time =  get_cmos_time();
-
-       clock_cmos_diff = -cmos_time;
-       clock_cmos_diff += get_seconds();
-       sleep_start = cmos_time;
-       return 0;
-}
-
-static int timer_resume(struct sys_device *dev)
-{
-       unsigned long flags;
-       unsigned long sec;
-       unsigned long ctime = get_cmos_time();
-       long sleep_length = (ctime - sleep_start) * HZ;
-
-       if (sleep_length < 0) {
-               printk(KERN_WARNING "Time skew detected in timer resume!\n");
-               /* The time after the resume must not be earlier than the time
-                * before the suspend or some nasty things will happen
-                */
-               sleep_length = 0;
-               ctime = sleep_start;
-       }
-       if (hpet_address)
-               hpet_reenable();
-       else
-               i8254_timer_resume();
-
-       sec = ctime + clock_cmos_diff;
-       write_seqlock_irqsave(&xtime_lock,flags);
-       xtime.tv_sec = sec;
-       xtime.tv_nsec = 0;
-       jiffies += sleep_length;
-       write_sequnlock_irqrestore(&xtime_lock,flags);
-       touch_softlockup_watchdog();
-       return 0;
-}
-
-static struct sysdev_class timer_sysclass = {
-       .resume = timer_resume,
-       .suspend = timer_suspend,
-       set_kset_name("timer"),
-};
-
-/* XXX this sysfs stuff should probably go elsewhere later -john */
-static struct sys_device device_timer = {
-       .id     = 0,
-       .cls    = &timer_sysclass,
-};
-
-static int time_init_device(void)
-{
-       int error = sysdev_class_register(&timer_sysclass);
-       if (!error)
-               error = sysdev_register(&device_timer);
-       return error;
-}
-
-device_initcall(time_init_device);
--- linus-2.6.orig/arch/x86_64/kernel/hpet.c
+++ linus-2.6/arch/x86_64/kernel/hpet.c
@@ -4,6 +4,7 @@
 #include <linux/mc146818rtc.h>
 #include <linux/time.h>
 #include <linux/clocksource.h>
+#include <linux/clockchips.h>
 #include <linux/ioport.h>
 #include <linux/acpi.h>
 #include <linux/hpet.h>
@@ -11,6 +12,7 @@
 #include <asm/vsyscall.h>
 #include <asm/timex.h>
 #include <asm/hpet.h>
+#include <asm/delay.h>
 
 #define HPET_MASK      0xFFFFFFFF
 #define HPET_SHIFT     22
@@ -27,6 +29,13 @@ unsigned long hpet_tick;     /* HPET clocks 
 int hpet_use_timer;            /* Use counter of hpet for time keeping,
                                 * otherwise PIT
                                 */
+static int hpet_legacy_int_enabled;
+extern struct clock_event_device *global_clock_event;
+
+static inline int is_hpet_capable(void)
+{
+       return (!nohpet && hpet_address);
+}
 
 #ifdef CONFIG_HPET
 static __init int late_hpet_init(void)
@@ -34,7 +43,7 @@ static __init int late_hpet_init(void)
        struct hpet_data        hd;
        unsigned int            ntimer;
 
-       if (!hpet_address)
+       if (!is_hpet_capable())
                return 0;
 
        memset(&hd, 0, sizeof(hd));
@@ -77,44 +86,107 @@ static __init int late_hpet_init(void)
 fs_initcall(late_hpet_init);
 #endif
 
-int hpet_timer_stop_set_go(unsigned long tick)
-{
-       unsigned int cfg;
+/*
+ * Common hpet info
+ */
+static void hpet_set_mode(enum clock_event_mode mode,
+                         struct clock_event_device *evt);
+static int hpet_next_event(unsigned long delta,
+                          struct clock_event_device *evt);
 
 /*
- * Stop the timers and reset the main counter.
+ * The hpet clock event device
  */
+struct clock_event_device hpet_clockevent = {
+       .name           = "hpet",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .set_mode       = hpet_set_mode,
+       .set_next_event = hpet_next_event,
+       .shift          = 32,
+       .irq            = 0,
+};
+
+static void hpet_start_counter(void)
+{
+       unsigned long cfg = hpet_readl(HPET_CFG);
 
-       cfg = hpet_readl(HPET_CFG);
-       cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
+       cfg &= ~HPET_CFG_ENABLE;
        hpet_writel(cfg, HPET_CFG);
        hpet_writel(0, HPET_COUNTER);
        hpet_writel(0, HPET_COUNTER + 4);
+       cfg |= HPET_CFG_ENABLE;
+       hpet_writel(cfg, HPET_CFG);
+}
 
-/*
- * Set up timer 0, as periodic with first interrupt to happen at hpet_tick,
- * and period also hpet_tick.
- */
-       if (hpet_use_timer) {
-               hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
-                   HPET_TN_32BIT, HPET_T0_CFG);
-               hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */
-               hpet_writel(hpet_tick, HPET_T0_CMP); /* period */
-               cfg |= HPET_CFG_LEGACY;
-       }
-/*
- * Go!
- */
+static void hpet_enable_int(void)
+{
+       unsigned long cfg = hpet_readl(HPET_CFG);
 
-       cfg |= HPET_CFG_ENABLE;
+       cfg |= HPET_CFG_LEGACY;
        hpet_writel(cfg, HPET_CFG);
+       hpet_legacy_int_enabled = 1;
+}
 
-       return 0;
+static void hpet_set_mode(enum clock_event_mode mode,
+                         struct clock_event_device *evt)
+{
+       unsigned long cfg, cmp, now;
+       uint64_t delta;
+
+       switch(mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * hpet_clockevent.mult;
+               delta >>= hpet_clockevent.shift;
+               now = hpet_readl(HPET_COUNTER);
+               cmp = now + (unsigned long) delta;
+               cfg = hpet_readl(HPET_T0_CFG);
+               cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
+                      HPET_TN_SETVAL | HPET_TN_32BIT;
+               hpet_writel(cfg, HPET_T0_CFG);
+               /*
+                * The first write after writing TN_SETVAL to the
+                * config register sets the counter value, the second
+                * write sets the period.
+                */
+               hpet_writel(cmp, HPET_T0_CMP);
+               udelay(1);
+               hpet_writel((unsigned int) delta, HPET_T0_CMP);
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+               cfg = hpet_readl(HPET_T0_CFG);
+               cfg &= ~HPET_TN_PERIODIC;
+               cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
+               hpet_writel(cfg, HPET_T0_CFG);
+               break;
+
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               cfg = hpet_readl(HPET_T0_CFG);
+               cfg &= ~HPET_TN_ENABLE;
+               hpet_writel(cfg, HPET_T0_CFG);
+               break;
+       }
+}
+
+static int hpet_next_event(unsigned long delta,
+                          struct clock_event_device *evt)
+{
+       unsigned long cnt;
+
+       cnt = hpet_readl(HPET_COUNTER);
+       cnt += delta;
+       hpet_writel(cnt, HPET_T0_CMP);
+
+       return ((long)(hpet_readl(HPET_COUNTER) - cnt ) > 0);
 }
 
+/*
+ * Clock source related code
+ */
 static cycle_t read_hpet(void)
 {
-       return (cycle_t)hpet_readl(HPET_COUNTER);
+       return hpet_readl(HPET_COUNTER);
 }
 
 static cycle_t __vsyscall_fn vread_hpet(void)
@@ -136,10 +208,12 @@ struct clocksource clocksource_hpet = {
 int hpet_arch_init(void)
 {
        unsigned int id;
+       uint64_t hpet_freq;
        u64 tmp;
 
-       if (!hpet_address)
-               return -1;
+       if (!is_hpet_capable())
+               return 0;
+
        set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
        __set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
 
@@ -150,15 +224,31 @@ int hpet_arch_init(void)
        id = hpet_readl(HPET_ID);
 
        if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER))
-               return -1;
+               return 0;
 
        hpet_period = hpet_readl(HPET_PERIOD);
        if (hpet_period < 100000 || hpet_period > 100000000)
-               return -1;
+               return 0;
+
+       /*
+        * The period is a femto seconds value. We need to calculate the
+        * scaled math multiplication factor for nanosecond to hpet tick
+        * conversion.
+        */
+       hpet_freq = 1000000000000000ULL;
+       do_div(hpet_freq, hpet_period);
+       hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
+                                     NSEC_PER_SEC, 32);
+       /* Calculate the min / max delta */
+       hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
+                                                          &hpet_clockevent);
+       hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
+                                                          &hpet_clockevent);
 
        hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period;
 
-       hpet_use_timer = (id & HPET_ID_LEGSUP);
+       /* Start the counter */
+       hpet_start_counter();
 
        /*
         * hpet period is in femto seconds per cycle
@@ -176,12 +266,20 @@ int hpet_arch_init(void)
        clocksource_hpet.mult = (u32)tmp;
        clocksource_register(&clocksource_hpet);
 
-       return hpet_timer_stop_set_go(hpet_tick);
-}
+       hpet_use_timer = (id & HPET_ID_LEGSUP);
 
-int hpet_reenable(void)
-{
-       return hpet_timer_stop_set_go(hpet_tick);
+       if (hpet_use_timer) {
+               hpet_enable_int();
+               /*
+                * Start hpet with the boot cpu mask and make it
+                * global after the IO_APIC has been initialized.
+                */
+               hpet_clockevent.cpumask = cpumask_of_cpu(0);
+               clockevents_register_device(&hpet_clockevent);
+               global_clock_event = &hpet_clockevent;
+               return 1;
+       }
+       return 0;
 }
 
 /*
@@ -265,7 +363,7 @@ static unsigned int hpet_t1_cmp; /* cach
 
 int is_hpet_enabled(void)
 {
-       return hpet_address != 0;
+       return is_hpet_capable() && hpet_legacy_int_enabled;
 }
 
 /*
--- linus-2.6.orig/arch/x86_64/Kconfig
+++ linus-2.6/arch/x86_64/Kconfig
@@ -28,6 +28,14 @@ config GENERIC_TIME
        bool
        default y
 
+config GENERIC_CLOCKEVENTS_BROADCAST
+       bool
+       default y
+
+config GENERIC_CLOCKEVENTS
+       bool
+       default y
+
 config GENERIC_TIME_VSYSCALL
        bool
        default y
--- linus-2.6.orig/arch/x86_64/kernel/apic.c
+++ linus-2.6/arch/x86_64/kernel/apic.c
@@ -26,6 +26,7 @@
 #include <linux/sysdev.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
+#include <linux/clockchips.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -62,6 +63,26 @@ static cpumask_t timer_interrupt_broadca
 /* Using APIC to generate smp_local_timer_interrupt? */
 int using_apic_timer __read_mostly = 0;
 
+
+static unsigned int calibration_result;
+
+static int lapic_next_event(unsigned long delta,
+                           struct clock_event_device *evt);
+static void lapic_timer_setup(enum clock_event_mode mode,
+                             struct clock_event_device *evt);
+
+static struct clock_event_device lapic_clockevent = {
+       .name           = "lapic",
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
+                       | CLOCK_EVT_FEAT_C3STOP,
+       .shift          = 32,
+       .set_mode       = lapic_timer_setup,
+       .set_next_event = lapic_next_event,
+       .rating         = 100,
+       .irq            = -1,
+};
+static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
+
 static void apic_pm_activate(void);
 
 void enable_NMI_through_LVT0 (void * dummy)
@@ -734,12 +755,15 @@ void __init init_apic_mappings(void)
 
 #define APIC_DIVISOR 16
 
-static void __setup_APIC_LVTT(unsigned int clocks)
+static void __setup_APIC_LVTT(unsigned int clocks, int oneshot)
 {
        unsigned int lvtt_value, tmp_value;
        int cpu = smp_processor_id();
 
-       lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
+       lvtt_value = LOCAL_TIMER_VECTOR;
+       if (!oneshot)
+               lvtt_value |= APIC_LVT_TIMER_PERIODIC;
+
 
        if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask))
                lvtt_value |= APIC_LVT_MASKED;
@@ -754,35 +778,24 @@ static void __setup_APIC_LVTT(unsigned i
                                & ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
                                | APIC_TDR_DIV_16);
 
-       apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
+       if (!oneshot)
+               apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
 }
 
-static void setup_APIC_timer(unsigned int clocks)
+static int lapic_next_event(unsigned long delta,
+                           struct clock_event_device *evt)
+{
+       apic_write(APIC_TMICT, delta);
+       return 0;
+}
+
+static void lapic_timer_setup(enum clock_event_mode mode,
+                             struct clock_event_device *evt)
 {
        unsigned long flags;
 
        local_irq_save(flags);
 
-       /* wait for irq slice */
-       if (hpet_address && hpet_use_timer) {
-               int trigger = hpet_readl(HPET_T0_CMP);
-               while (hpet_readl(HPET_COUNTER) >= trigger)
-                       /* do nothing */ ;
-               while (hpet_readl(HPET_COUNTER) <  trigger)
-                       /* do nothing */ ;
-       } else {
-               int c1, c2;
-               outb_p(0x00, 0x43);
-               c2 = inb_p(0x40);
-               c2 |= inb_p(0x40) << 8;
-               do {
-                       c1 = c2;
-                       outb_p(0x00, 0x43);
-                       c2 = inb_p(0x40);
-                       c2 |= inb_p(0x40) << 8;
-               } while (c2 - c1 < 300);
-       }
-       __setup_APIC_LVTT(clocks);
        /* Turn off PIT interrupt if we use APIC timer as main timer.
           Only works with the PM timer right now
           TBD fix it for HPET too. */
@@ -793,9 +806,33 @@ static void setup_APIC_timer(unsigned in
                stop_timer_interrupt();
                apic_runs_main_timer++;
        }
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+       case CLOCK_EVT_MODE_ONESHOT:
+               __setup_APIC_LVTT(calibration_result,
+                                 mode != CLOCK_EVT_MODE_PERIODIC);
+               break;
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               disable_APIC_timer();
+               break;
+       }
+
        local_irq_restore(flags);
 }
 
+
+static void __devinit setup_APIC_timer(void)
+{
+       struct clock_event_device *levt = &__get_cpu_var(lapic_events);
+
+       memcpy(levt, &lapic_clockevent, sizeof(*levt));
+       levt->cpumask = cpumask_of_cpu(smp_processor_id());
+
+       clockevents_register_device(levt);
+}
+
 /*
  * In this function we calibrate APIC bus clocks to the external
  * timer. Unfortunately we cannot use jiffies and the timer irq
@@ -815,12 +852,13 @@ static int __init calibrate_APIC_clock(v
 {
        int apic, apic_start, tsc, tsc_start;
        int result;
+       u64 wallclock_nsecs;
        /*
         * Put whatever arbitrary (but long enough) timeout
         * value into the APIC clock, we just want to get the
         * counter running for calibration.
         */
-       __setup_APIC_LVTT(1000000000);
+       __setup_APIC_LVTT(1000000000, 0);
 
        apic_start = apic_read(APIC_TMCCT);
 #ifdef CONFIG_X86_PM_TIMER
@@ -828,6 +866,8 @@ static int __init calibrate_APIC_clock(v
                pmtimer_wait(5000);  /* 5ms wait */
                apic = apic_read(APIC_TMCCT);
                result = (apic_start - apic) * 1000L / 5;
+               printk("using pmtimer for lapic calibration\n");
+               wallclock_nsecs = 5000000;
        } else
 #endif
        {
@@ -841,6 +881,8 @@ static int __init calibrate_APIC_clock(v
 
                result = (apic_start - apic) * 1000L * cpu_khz /
                                        (tsc - tsc_start);
+               wallclock_nsecs = ((u64)tsc - (u64)tsc_start) * 1000000 / 
(u64)cpu_khz;
+
        }
        printk("result %d\n", result);
 
@@ -848,11 +890,22 @@ static int __init calibrate_APIC_clock(v
        printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
                result / 1000 / 1000, result / 1000 % 1000);
 
+
+
+
+       /* Calculate the scaled math multiplication factor */
+       lapic_clockevent.mult = div_sc(apic_start - apic, wallclock_nsecs, 32);
+
+       lapic_clockevent.max_delta_ns =
+               clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
+       printk("lapic max_delta_ns: %ld\n", lapic_clockevent.max_delta_ns);
+       lapic_clockevent.min_delta_ns =
+               clockevent_delta2ns(0xF, &lapic_clockevent);
+
+
        return result * APIC_DIVISOR / HZ;
 }
 
-static unsigned int calibration_result;
-
 void __init setup_boot_APIC_clock (void)
 {
        if (disable_apic_timer) { 
@@ -869,7 +922,7 @@ void __init setup_boot_APIC_clock (void)
        /*
         * Now set up the timer for real.
         */
-       setup_APIC_timer(calibration_result);
+       setup_APIC_timer();
 
        local_irq_enable();
 }
@@ -877,7 +930,7 @@ void __init setup_boot_APIC_clock (void)
 void __cpuinit setup_secondary_APIC_clock(void)
 {
        local_irq_disable(); /* FIXME: Do we need this? --RR */
-       setup_APIC_timer(calibration_result);
+       setup_APIC_timer();
        local_irq_enable();
 }
 
@@ -924,6 +977,13 @@ void switch_APIC_timer_to_ipi(void *cpum
            !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
                disable_APIC_timer();
                cpu_set(cpu, timer_interrupt_broadcast_ipi_mask);
+#ifdef CONFIG_HIGH_RES_TIMERS
+               printk("Disabling NO_HZ and high resolution timers "
+                       "due to timer broadcasting\n");
+               for_each_possible_cpu(cpu)
+                       per_cpu(lapic_events, cpu).features &=
+                               ~CLOCK_EVT_FEAT_ONESHOT;
+#endif
        }
 }
 EXPORT_SYMBOL(switch_APIC_timer_to_ipi);
@@ -1008,6 +1068,9 @@ void smp_apic_timer_interrupt(struct pt_
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
 
+       int cpu = smp_processor_id();
+       struct clock_event_device *evt = &per_cpu(lapic_events, cpu);
+
        /*
         * the NMI deadlock-detector uses this.
         */
@@ -1025,7 +1088,7 @@ void smp_apic_timer_interrupt(struct pt_
         */
        exit_idle();
        irq_enter();
-       smp_local_timer_interrupt();
+       evt->event_handler(evt);
        irq_exit();
        set_irq_regs(old_regs);
 }
--- linus-2.6.orig/include/asm-x86_64/hpet.h
+++ linus-2.6/include/asm-x86_64/hpet.h
@@ -56,8 +56,6 @@
 extern int is_hpet_enabled(void);
 extern int hpet_rtc_timer_init(void);
 extern int hpet_arch_init(void);
-extern int hpet_timer_stop_set_go(unsigned long tick);
-extern int hpet_reenable(void);
 extern unsigned int hpet_calibrate_tsc(void);
 
 extern int hpet_use_timer;

--
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to