]> err.no Git - linux-2.6/blobdiff - arch/x86_64/kernel/hpet.c
Merge branch 'audit.b39' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit...
[linux-2.6] / arch / x86_64 / kernel / hpet.c
index 08ab37c966c223da7f83a5d2be67d06952ea0b7d..e2d1b912e15469c1110553fa3ebc27c97fc3af9e 100644 (file)
 #include <asm/timex.h>
 #include <asm/hpet.h>
 
+#define HPET_MASK      0xFFFFFFFF
+#define HPET_SHIFT     22
+
+/* FSEC = 10^-15 NSEC = 10^-9 */
+#define FSEC_PER_NSEC  1000000
+
 int nohpet __initdata;
 
 unsigned long hpet_address;
@@ -21,12 +27,6 @@ unsigned long hpet_tick;     /* HPET clocks / interrupt */
 int hpet_use_timer;            /* Use counter of hpet for time keeping,
                                 * otherwise PIT
                                 */
-unsigned int do_gettimeoffset_hpet(void)
-{
-       /* cap counter read to one tick to avoid inconsistencies */
-       unsigned long counter = hpet_readl(HPET_COUNTER) - vxtime.last;
-       return (min(counter,hpet_tick) * vxtime.quot) >> US_SCALE;
-}
 
 #ifdef CONFIG_HPET
 static __init int late_hpet_init(void)
@@ -112,9 +112,31 @@ int hpet_timer_stop_set_go(unsigned long tick)
        return 0;
 }
 
-int hpet_arch_init(void)
+static cycle_t read_hpet(void)
+{
+       return (cycle_t)hpet_readl(HPET_COUNTER);
+}
+
+static cycle_t __vsyscall_fn vread_hpet(void)
+{
+       return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
+}
+
+struct clocksource clocksource_hpet = {
+       .name           = "hpet",
+       .rating         = 250,
+       .read           = read_hpet,
+       .mask           = (cycle_t)HPET_MASK,
+       .mult           = 0, /* set below */
+       .shift          = HPET_SHIFT,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+       .vread          = vread_hpet,
+};
+
+int __init hpet_arch_init(void)
 {
        unsigned int id;
+       u64 tmp;
 
        if (!hpet_address)
                return -1;
@@ -138,6 +160,22 @@ int hpet_arch_init(void)
 
        hpet_use_timer = (id & HPET_ID_LEGSUP);
 
+       /*
+        * hpet period is in femto seconds per cycle
+        * so we need to convert this to ns/cyc units
+        * aproximated by mult/2^shift
+        *
+        *  fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
+        *  fsec/cyc * 1ns/1000000fsec * 2^shift = mult
+        *  fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
+        *  (fsec/cyc << shift)/1000000 = mult
+        *  (hpet_period << shift)/FSEC_PER_NSEC = mult
+        */
+       tmp = (u64)hpet_period << HPET_SHIFT;
+       do_div(tmp, FSEC_PER_NSEC);
+       clocksource_hpet.mult = (u32)tmp;
+       clocksource_register(&clocksource_hpet);
+
        return hpet_timer_stop_set_go(hpet_tick);
 }
 
@@ -152,7 +190,8 @@ int hpet_reenable(void)
  */
 
 #define TICK_COUNT 100000000
-#define TICK_MIN   5000
+#define SMI_THRESHOLD 50000
+#define MAX_TRIES  5
 
 /*
  * Some platforms take periodic SMI interrupts with 5ms duration. Make sure none
@@ -160,13 +199,15 @@ int hpet_reenable(void)
  */
 static void __init read_hpet_tsc(int *hpet, int *tsc)
 {
-       int tsc1, tsc2, hpet1;
+       int tsc1, tsc2, hpet1, i;
 
-       do {
+       for (i = 0; i < MAX_TRIES; i++) {
                tsc1 = get_cycles_sync();
                hpet1 = hpet_readl(HPET_COUNTER);
                tsc2 = get_cycles_sync();
-       } while (tsc2 - tsc1 > TICK_MIN);
+               if ((tsc2 - tsc1) < SMI_THRESHOLD)
+                       break;
+       }
        *hpet = hpet1;
        *tsc = tsc2;
 }
@@ -398,7 +439,7 @@ int hpet_rtc_dropped_irq(void)
        return 1;
 }
 
-irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
 {
        struct rtc_time curr_time;
        unsigned long rtc_int_flag = 0;
@@ -450,4 +491,3 @@ static int __init nohpet_setup(char *s)
 }
 
 __setup("nohpet", nohpet_setup);
-