aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--xen/arch/x86/crash.c2
-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, 38 insertions, 2 deletions
diff --git a/xen/arch/x86/crash.c b/xen/arch/x86/crash.c
index a76f9aca20..2faeb3fd18 100644
--- a/xen/arch/x86/crash.c
+++ b/xen/arch/x86/crash.c
@@ -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();
}
diff --git a/xen/arch/x86/hpet.c b/xen/arch/x86/hpet.c
index ca6a0297a0..e0b8659554 100644
--- a/xen/arch/x86/hpet.c
+++ b/xen/arch/x86/hpet.c
@@ -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);
+}
diff --git a/xen/arch/x86/smp.c b/xen/arch/x86/smp.c
index 61b93a8b26..393e957f8f 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>
@@ -362,6 +363,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.
*/