[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 1/4] x86/hpet: disable before reboot or kexec


  • To: "xen-devel" <xen-devel@xxxxxxxxxxxxx>
  • From: "Jan Beulich" <JBeulich@xxxxxxxx>
  • Date: Tue, 27 Mar 2012 11:45:33 +0100
  • Delivery-date: Tue, 27 Mar 2012 10:45:04 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xen.org>

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@xxxxxxxx>

--- a/xen/arch/x86/crash.c
+++ b/xen/arch/x86/crash.c
@@ -96,6 +96,7 @@ static void nmi_shootdown_cpus(void)
 #endif
 
     disable_IO_APIC();
+    hpet_disable();
 }
 
 void machine_crash_shutdown(void)
--- a/xen/arch/x86/hpet.c
+++ b/xen/arch/x86/hpet.c
@@ -566,7 +566,7 @@ void hpet_broadcast_resume(void)
     if ( !hpet_events )
         return;
 
-    hpet_resume();
+    hpet_resume(NULL);
 
     cfg = hpet_read32(HPET_CFG);
 
@@ -704,10 +704,13 @@ int hpet_legacy_irq_tick(void)
     return 1;
 }
 
+static u32 *hpet_boot_cfg;
+
 u64 __init hpet_setup(void)
 {
     static u64 __initdata hpet_rate;
     u32 hpet_id, hpet_period;
+    unsigned int last;
 
     if ( hpet_rate )
         return hpet_rate;
@@ -732,7 +735,9 @@ u64 __init hpet_setup(void)
         return 0;
     }
 
-    hpet_resume();
+    last = (hpet_id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
+    hpet_boot_cfg = xmalloc_array(u32, 2 + last);
+    hpet_resume(hpet_boot_cfg);
 
     hpet_rate = 1000000000000000ULL; /* 10^15 */
     (void)do_div(hpet_rate, hpet_period);
@@ -740,24 +745,29 @@ u64 __init hpet_setup(void)
     return hpet_rate;
 }
 
-void hpet_resume(void)
+void hpet_resume(u32 *boot_cfg)
 {
     static u32 system_reset_latch;
     u32 hpet_id, cfg;
-    unsigned int i;
+    unsigned int i, last;
 
     if ( system_reset_latch == system_reset_counter )
         return;
     system_reset_latch = system_reset_counter;
 
     cfg = hpet_read32(HPET_CFG);
+    if ( boot_cfg )
+        *boot_cfg = cfg;
     cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
     hpet_write32(cfg, HPET_CFG);
 
     hpet_id = hpet_read32(HPET_ID);
-    for ( i = 0; i <= ((hpet_id >> 8) & 31); i++ )
+    last = (hpet_id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
+    for ( i = 0; i <= last; ++i )
     {
         cfg = hpet_read32(HPET_Tn_CFG(i));
+        if ( boot_cfg )
+            boot_cfg[i + 1] = cfg;
         cfg &= ~HPET_TN_ENABLE;
         hpet_write32(cfg, HPET_Tn_CFG(i));
     }
@@ -766,3 +776,21 @@ void hpet_resume(void)
     cfg |= HPET_CFG_ENABLE;
     hpet_write32(cfg, HPET_CFG);
 }
+
+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);
+}
--- a/xen/arch/x86/smp.c
+++ b/xen/arch/x86/smp.c
@@ -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>
 
@@ -375,6 +376,7 @@ void smp_send_stop(void)
     local_irq_disable();
     __stop_this_cpu();
     disable_IO_APIC();
+    hpet_disable();
     local_irq_enable();
 }
 
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -377,7 +377,7 @@ static int __init init_hpet(struct platf
 
 static void resume_hpet(struct platform_timesource *pts)
 {
-    hpet_resume();
+    hpet_resume(NULL);
 }
 
 static struct platform_timesource __initdata plt_hpet =
--- a/xen/include/asm-x86/hpet.h
+++ b/xen/include/asm-x86/hpet.h
@@ -55,7 +55,12 @@ extern unsigned long hpet_address;
  * Return value is zero if HPET is unavailable.
  */
 u64 hpet_setup(void);
-void hpet_resume(void);
+void hpet_resume(u32 *);
+
+/*
+ * Disable HPET hardware: restore it to boot time state.
+ */
+void hpet_disable(void);
 
 /*
  * Callback from legacy timer (PIT channel 0) IRQ handler.


Attachment: x86-hpet-disable.patch
Description: Text document

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.