126 lines
3.4 KiB
Diff
126 lines
3.4 KiB
Diff
|
References: bnc#748896
|
||
|
|
||
|
# HG changeset patch
|
||
|
# User Jan Beulich <jbeulich@suse.com>
|
||
|
# Date 1332854423 -7200
|
||
|
# Node ID f06ff3dfde08ee563970cffba502742249ff5820
|
||
|
# Parent ed48258053aea953afd28b746b53af7b8b30531b
|
||
|
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>
|
||
|
|
||
|
--- 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)
|
||
|
--- a/xen/arch/x86/hpet.c
|
||
|
+++ b/xen/arch/x86/hpet.c
|
||
|
@@ -721,12 +721,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;
|
||
|
@@ -752,13 +754,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));
|
||
|
}
|
||
|
@@ -772,3 +781,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);
|
||
|
+}
|
||
|
--- 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>
|
||
|
|
||
|
@@ -373,6 +374,7 @@ void smp_send_stop(void)
|
||
|
local_irq_disable();
|
||
|
__stop_this_cpu();
|
||
|
disable_IO_APIC();
|
||
|
+ hpet_disable();
|
||
|
local_irq_enable();
|
||
|
}
|
||
|
|
||
|
--- a/xen/include/asm-x86/hpet.h
|
||
|
+++ b/xen/include/asm-x86/hpet.h
|
||
|
@@ -68,6 +68,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.
|
||
|
*/
|