]> err.no Git - linux-2.6/blobdiff - arch/x86/kernel/hpet.c
[PACKET]: Fix sparse warnings in af_packet.c
[linux-2.6] / arch / x86 / kernel / hpet.c
index dbe0e1d44113498d6e4bfb4b3ba752ed11619378..2f99ee206b9527c3cad6250caa95e2a3ceac9268 100644 (file)
 unsigned long hpet_address;
 static void __iomem *hpet_virt_address;
 
-/* Temporary hack. Cleanup after x86_64 clock events conversion */
-#undef hpet_readl
-#undef hpet_writel
-
-static inline unsigned long hpet_readl(unsigned long a)
+unsigned long hpet_readl(unsigned long a)
 {
        return readl(hpet_virt_address + a);
 }
@@ -73,12 +69,15 @@ static inline void hpet_clear_mapping(void)
  * HPET command line enable / disable
  */
 static int boot_hpet_disable;
+int hpet_force_user;
 
 static int __init hpet_setup(char* str)
 {
        if (str) {
                if (!strncmp("disable", str, 7))
                        boot_hpet_disable = 1;
+               if (!strncmp("force", str, 5))
+                       hpet_force_user = 1;
        }
        return 1;
 }
@@ -153,9 +152,9 @@ static void hpet_reserve_platform_timers(unsigned long id) { }
  */
 static unsigned long hpet_period;
 
-static void hpet_set_mode(enum clock_event_mode mode,
+static void hpet_legacy_set_mode(enum clock_event_mode mode,
                          struct clock_event_device *evt);
-static int hpet_next_event(unsigned long delta,
+static int hpet_legacy_next_event(unsigned long delta,
                           struct clock_event_device *evt);
 
 /*
@@ -164,10 +163,11 @@ static int hpet_next_event(unsigned long delta,
 static 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,
+       .set_mode       = hpet_legacy_set_mode,
+       .set_next_event = hpet_legacy_next_event,
        .shift          = 32,
        .irq            = 0,
+       .rating         = 50,
 };
 
 static void hpet_start_counter(void)
@@ -182,7 +182,18 @@ static void hpet_start_counter(void)
        hpet_writel(cfg, HPET_CFG);
 }
 
-static void hpet_enable_int(void)
+static void hpet_resume_device(void)
+{
+       force_hpet_resume();
+}
+
+static void hpet_restart_counter(void)
+{
+       hpet_resume_device();
+       hpet_start_counter();
+}
+
+static void hpet_enable_legacy_int(void)
 {
        unsigned long cfg = hpet_readl(HPET_CFG);
 
@@ -191,7 +202,39 @@ static void hpet_enable_int(void)
        hpet_legacy_int_enabled = 1;
 }
 
-static void hpet_set_mode(enum clock_event_mode mode,
+static void hpet_legacy_clockevent_register(void)
+{
+       uint64_t hpet_freq;
+
+       /* Start HPET legacy interrupts */
+       hpet_enable_legacy_int();
+
+       /*
+        * 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);
+
+       /*
+        * Start hpet with the boot cpu mask and make it
+        * global after the IO_APIC has been initialized.
+        */
+       hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
+       clockevents_register_device(&hpet_clockevent);
+       global_clock_event = &hpet_clockevent;
+       printk(KERN_DEBUG "hpet clockevent registered\n");
+}
+
+static void hpet_legacy_set_mode(enum clock_event_mode mode,
                          struct clock_event_device *evt)
 {
        unsigned long cfg, cmp, now;
@@ -232,12 +275,12 @@ static void hpet_set_mode(enum clock_event_mode mode,
                break;
 
        case CLOCK_EVT_MODE_RESUME:
-               hpet_enable_int();
+               hpet_enable_legacy_int();
                break;
        }
 }
 
-static int hpet_next_event(unsigned long delta,
+static int hpet_legacy_next_event(unsigned long delta,
                           struct clock_event_device *evt)
 {
        unsigned long cnt;
@@ -271,64 +314,17 @@ static struct clocksource clocksource_hpet = {
        .mask           = HPET_MASK,
        .shift          = HPET_SHIFT,
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-       .resume         = hpet_start_counter,
+       .resume         = hpet_restart_counter,
 #ifdef CONFIG_X86_64
        .vread          = vread_hpet,
 #endif
 };
 
-/*
- * Try to setup the HPET timer
- */
-int __init hpet_enable(void)
+static int hpet_clocksource_register(void)
 {
-       unsigned long id;
-       uint64_t hpet_freq;
        u64 tmp, start, now;
        cycle_t t1;
 
-       if (!is_hpet_capable())
-               return 0;
-
-       hpet_set_mapping();
-
-       /*
-        * Read the period and check for a sane value:
-        */
-       hpet_period = hpet_readl(HPET_PERIOD);
-       if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
-               goto out_nohpet;
-
-       /*
-        * 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);
-
-       /*
-        * Read the HPET ID register to retrieve the IRQ routing
-        * information and the number of channels
-        */
-       id = hpet_readl(HPET_ID);
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-       /*
-        * The legacy routing mode needs at least two channels, tick timer
-        * and the rtc emulation channel.
-        */
-       if (!(id & HPET_ID_NUMBER))
-               goto out_nohpet;
-#endif
-
        /* Start the counter */
        hpet_start_counter();
 
@@ -350,14 +346,14 @@ int __init hpet_enable(void)
        if (t1 == read_hpet()) {
                printk(KERN_WARNING
                       "HPET counter not counting. HPET disabled\n");
-               goto out_nohpet;
+               return -ENODEV;
        }
 
        /* Initialize and register HPET clocksource
         *
         * hpet period is in femto seconds per cycle
         * so we need to convert this to ns/cyc units
-        * aproximated by mult/2^shift
+        * approximated by mult/2^shift
         *
         *  fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
         *  fsec/cyc * 1ns/1000000fsec * 2^shift = mult
@@ -371,15 +367,48 @@ int __init hpet_enable(void)
 
        clocksource_register(&clocksource_hpet);
 
+       return 0;
+}
+
+/*
+ * Try to setup the HPET timer
+ */
+int __init hpet_enable(void)
+{
+       unsigned long id;
+
+       if (!is_hpet_capable())
+               return 0;
+
+       hpet_set_mapping();
+
+       /*
+        * Read the period and check for a sane value:
+        */
+       hpet_period = hpet_readl(HPET_PERIOD);
+       if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
+               goto out_nohpet;
+
+       /*
+        * Read the HPET ID register to retrieve the IRQ routing
+        * information and the number of channels
+        */
+       id = hpet_readl(HPET_ID);
+
+#ifdef CONFIG_HPET_EMULATE_RTC
+       /*
+        * The legacy routing mode needs at least two channels, tick timer
+        * and the rtc emulation channel.
+        */
+       if (!(id & HPET_ID_NUMBER))
+               goto out_nohpet;
+#endif
+
+       if (hpet_clocksource_register())
+               goto out_nohpet;
+
        if (id & HPET_ID_LEGSUP) {
-               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(smp_processor_id());
-               clockevents_register_device(&hpet_clockevent);
-               global_clock_event = &hpet_clockevent;
+               hpet_legacy_clockevent_register();
                return 1;
        }
        return 0;
@@ -398,14 +427,39 @@ out_nohpet:
  */
 static __init int hpet_late_init(void)
 {
-       if (!is_hpet_capable())
+       if (boot_hpet_disable)
                return -ENODEV;
 
+       if (!hpet_address) {
+               if (!force_hpet_address)
+                       return -ENODEV;
+
+               hpet_address = force_hpet_address;
+               hpet_enable();
+               if (!hpet_virt_address)
+                       return -ENODEV;
+       }
+
        hpet_reserve_platform_timers(hpet_readl(HPET_ID));
+
        return 0;
 }
 fs_initcall(hpet_late_init);
 
+void hpet_disable(void)
+{
+       if (is_hpet_capable()) {
+               unsigned long cfg = hpet_readl(HPET_CFG);
+
+               if (hpet_legacy_int_enabled) {
+                       cfg &= ~HPET_CFG_LEGACY;
+                       hpet_legacy_int_enabled = 0;
+               }
+               cfg &= ~HPET_CFG_ENABLE;
+               hpet_writel(cfg, HPET_CFG);
+       }
+}
+
 #ifdef CONFIG_HPET_EMULATE_RTC
 
 /* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET
@@ -603,7 +657,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
                hpet_pie_count = 0;
        }
 
-       if (hpet_rtc_flags & RTC_PIE &&
+       if (hpet_rtc_flags & RTC_AIE &&
            (curr_time.tm_sec == hpet_alarm_time.tm_sec) &&
            (curr_time.tm_min == hpet_alarm_time.tm_min) &&
            (curr_time.tm_hour == hpet_alarm_time.tm_hour))