]> xenbits.xensource.com Git - xen.git/commitdiff
x86/hpet: disable before reboot or kexec
authorJan Beulich <jbeulich@suse.com>
Tue, 17 Apr 2012 07:37:47 +0000 (08:37 +0100)
committerJan Beulich <jbeulich@suse.com>
Tue, 17 Apr 2012 07:37:47 +0000 (08:37 +0100)
Linux up to now is not smart enough to properly clear the HPET when it
boots, which is particularly a problem when a kdump attempt from
running under Xen is being made. Linux itself added code to work
around
this to its shutdown paths quite some time ago, so let's do something
similar in Xen: Save the configuration register settings during boot,
and restore them during shutdown. This should cover the majority of
cases where the secondary kernel might not come up because timer
interrupts don't work.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Keir Fraser <keir@xen.org>
xen-unstable changeset:   25101:f06ff3dfde08
xen-unstable date:        Tue Mar 27 15:20:23 2012 +0200

xen/arch/x86/crash.c
xen/arch/x86/hpet.c
xen/arch/x86/smp.c
xen/include/asm-x86/hpet.h

index a76f9aca2075c25093be31a27c28043cd125f47b..2faeb3fd18274efd0095c0d08fb0c0ec8f89657d 100644 (file)
@@ -25,6 +25,7 @@
 #include <public/xen.h>
 #include <asm/shared.h>
 #include <asm/hvm/support.h>
+#include <asm/hpet.h>
 
 static atomic_t waiting_for_crash_ipi;
 static unsigned int crashing_cpu;
@@ -77,6 +78,7 @@ static void nmi_shootdown_cpus(void)
 
     __stop_this_cpu();
     disable_IO_APIC();
+    hpet_disable();
 
     local_irq_enable();
 }
index ca6a0297a0466fa1a802abde93e754f5aff18750..e0b865955481574cacd9658e3a835d1a5eb98d67 100644 (file)
@@ -722,12 +722,14 @@ int hpet_legacy_irq_tick(void)
     return 1;
 }
 
+static u32 *hpet_boot_cfg;
+
 u64 hpet_setup(void)
 {
     static u64 hpet_rate;
     static u32 system_reset_latch;
     u32 hpet_id, hpet_period, cfg;
-    int i;
+    unsigned int i, last;
 
     if ( system_reset_latch == system_reset_counter )
         return hpet_rate;
@@ -753,13 +755,20 @@ u64 hpet_setup(void)
         return 0;
     }
 
+    last = (hpet_id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
+    hpet_boot_cfg = xmalloc_array(u32, 2 + last);
+
     cfg = hpet_read32(HPET_CFG);
+    if ( hpet_boot_cfg )
+        *hpet_boot_cfg = cfg;
     cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
     hpet_write32(cfg, HPET_CFG);
 
-    for ( i = 0; i <= ((hpet_id >> 8) & 31); i++ )
+    for ( i = 0; i <= last; ++i )
     {
         cfg = hpet_read32(HPET_Tn_CFG(i));
+        if ( hpet_boot_cfg )
+            hpet_boot_cfg[i + 1] = cfg;
         cfg &= ~HPET_TN_ENABLE;
         hpet_write32(cfg, HPET_Tn_CFG(i));
     }
@@ -773,3 +782,21 @@ u64 hpet_setup(void)
 
     return hpet_rate;
 }
+
+void hpet_disable(void)
+{
+    unsigned int i;
+    u32 id;
+
+    if ( !hpet_boot_cfg )
+        return;
+
+    hpet_write32(*hpet_boot_cfg & ~HPET_CFG_ENABLE, HPET_CFG);
+
+    id = hpet_read32(HPET_ID);
+    for ( i = 0; i <= ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT); ++i )
+        hpet_write32(hpet_boot_cfg[i + 1], HPET_Tn_CFG(i));
+
+    if ( *hpet_boot_cfg & HPET_CFG_ENABLE )
+        hpet_write32(*hpet_boot_cfg, HPET_CFG);
+}
index 61b93a8b2683dc9b3f8d7920fe38ee31b7852f7c..393e957f8f9053bb25eb663bef467ef3de5765ae 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/mc146818rtc.h>
 #include <asm/flushtlb.h>
 #include <asm/hardirq.h>
+#include <asm/hpet.h>
 #include <asm/hvm/support.h>
 #include <mach_apic.h>
 
@@ -362,6 +363,7 @@ void smp_send_stop(void)
     local_irq_disable();
     __stop_this_cpu();
     disable_IO_APIC();
+    hpet_disable();
     local_irq_enable();
 }
 
index da08880f6cb797e5a5acc6c716db7e97aa833c80..2f18ba02837b0a2172c31b41d60240f2e026bce5 100644 (file)
@@ -66,6 +66,11 @@ extern unsigned long hpet_address;
  */
 u64 hpet_setup(void);
 
+/*
+ * Disable HPET hardware: restore it to boot time state.
+ */
+void hpet_disable(void);
+
 /*
  * Callback from legacy timer (PIT channel 0) IRQ handler.
  * Returns 1 if tick originated from HPET; else 0.