aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2012-04-17 08:35:09 +0100
committerJan Beulich <jbeulich@suse.com>2012-04-17 08:35:09 +0100
commit0c5b76d2bd2fbe242b1d3d415af1a5482c653e9a (patch)
treed70ce911967777cd46e719c1f35fccf654fb9924
parentee312640a24f7527327f1b826b4cb58d08c90ce1 (diff)
downloadxen-0c5b76d2bd2fbe242b1d3d415af1a5482c653e9a.tar.gz
xen-0c5b76d2bd2fbe242b1d3d415af1a5482c653e9a.tar.bz2
xen-0c5b76d2bd2fbe242b1d3d415af1a5482c653e9a.zip
x86/hpet: disable before reboot or kexec
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
-rw-r--r--xen/arch/x86/crash.c1
-rw-r--r--xen/arch/x86/hpet.c31
-rw-r--r--xen/arch/x86/smp.c2
-rw-r--r--xen/include/asm-x86/hpet.h5
4 files changed, 37 insertions, 2 deletions
diff --git a/xen/arch/x86/crash.c b/xen/arch/x86/crash.c
index 68174b51fa..0e1afa67dd 100644
--- a/xen/arch/x86/crash.c
+++ b/xen/arch/x86/crash.c
@@ -94,6 +94,7 @@ static void nmi_shootdown_cpus(void)
x2apic_enabled = (current_local_apic_mode() == APIC_MODE_X2APIC);
disable_IO_APIC();
+ hpet_disable();
}
void machine_crash_shutdown(void)
diff --git a/xen/arch/x86/hpet.c b/xen/arch/x86/hpet.c
index 454ef732e0..fecc02cd14 100644
--- a/xen/arch/x86/hpet.c
+++ b/xen/arch/x86/hpet.c
@@ -744,12 +744,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;
@@ -775,13 +777,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));
}
@@ -795,3 +804,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);
+}
diff --git a/xen/arch/x86/smp.c b/xen/arch/x86/smp.c
index 2f527079cd..88cc9a0cef 100644
--- 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>
@@ -372,6 +373,7 @@ void smp_send_stop(void)
local_irq_disable();
__stop_this_cpu();
disable_IO_APIC();
+ hpet_disable();
local_irq_enable();
}
diff --git a/xen/include/asm-x86/hpet.h b/xen/include/asm-x86/hpet.h
index da08880f6c..2f18ba0283 100644
--- a/xen/include/asm-x86/hpet.h
+++ b/xen/include/asm-x86/hpet.h
@@ -67,6 +67,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.
*/