x86: disable AMD's C1E mode
PATCH 1/1 x86: disable AMD's C1E mode
In C1E the APIC timer stops ticking, which Xen cannot tolerate. (As I don't have a system that's affected, the patch must be considered untested).
Signed-off-by Jan Beulich <[email protected]>
xen/arch/x86/acpi/boot.c +8 -0
@@ -70,6 +70,9 @@ int acpi_skip_timer_override __initdata;static u64 acpi_lapic_addr__initdata =APIC_DEFAULT_PHYS_BASE ;#endif +u32 acpi_smi_cmd; +u8 acpi_enable_value, acpi_disable_value; +#ifndef __HAVE_ARCH_CMPXCHG#warning ACPI uses CMPXCHG, i486 and later hardware#endif
@@ -509,9 +512,14 @@ static int __init acpi_parse_fadt(unsign pmtmr_ioport);#endif + acpi_smi_cmd = fadt->smi_cmd; + acpi_enable_value = fadt->acpi_enable; + acpi_disable_value = fadt->acpi_disable; +#ifdef CONFIG_ACPI_SLEEP acpi_fadt_parse_sleep_info (fadt);#endif +return 0 ; }
xen/arch/x86/cpu/amd.c +30 -0
@@ -100,6 +100,32 @@ static void disable_c1_ramping(void) } } +#ifdef CONFIG_SMP +/* +* Disable C1E mode, as the APIC timer stops in that mode. +*/ +static void disable_c1e (void *unused) +{ +u32 lo, hi; + +if (rdmsr_safe (0xC0010055 , lo, hi) ==0 + && (lo & ((1 <<27 ) | (1 <<28 ))) + &&wrmsr_safe (0xC0010055 , + lo & ~((1 <<27 ) | (1 <<28 )), + hi) !=0 ) +printk (KERN_ERR "Failed to disable C1E on CPU#%u (%08x)\n" , +smp_processor_id (), lo); +} + +static void check_disable_c1e (unsigned int port,u8 value) +{ +if (port == acpi_smi_cmd && value == acpi_enable_value) +on_each_cpu (disable_c1e,NULL ,1 ,1 ); +} +#else +#define check_disable_c1e NULL +#endif +static void __init init_amd (struct cpuinfo_x86 *c) {u32 l, h;
@@ -280,6 +306,10 @@ static void __init init_amd(struct cpuinswitch (c->x86) { case 15 ... 17:set_bit (X86_FEATURE_K8 , c->x86_capability); +if (acpi_smi_cmd && (acpi_enable_value | acpi_disable_value)) { +disable_c1e (NULL ); + pv_post_outb_hook = check_disable_c1e; + }break ;case 6 :set_bit (X86_FEATURE_K7 , c->x86_capability);
xen/arch/x86/traps.c +10 -0
@@ -1191,6 +1191,8 @@ void host_to_guest_gpr_switch(struct cpuunsigned long guest_to_host_gpr_switch (unsigned long ) __attribute__((__regparm__ (1 ))); +void (*pv_post_outb_hook)(unsigned int port,u8 value); +/* Instruction fetch with error handling. */ #define insn_fetch (type, base, eip, limit) \ ({ unsigned long _rc, _ptr = (base) + (eip); \
@@ -1419,7 +1421,11 @@ static int emulate_privileged_op(struct {case 1 :if (guest_outb_okay (port, v, regs) ) + {outb ((u8 )data, port); +if ( pv_post_outb_hook ) +pv_post_outb_hook (port, data); + }else if ( port ==0x42 || port ==0x43 || port ==0x61 )pv_pit_handler (port, data,1 );break ;
@@ -1537,7 +1543,11 @@ static int emulate_privileged_op(struct {case 1 :if (guest_outb_okay (port, v, regs) ) + {io_emul (regs); +if ( pv_post_outb_hook ) +pv_post_outb_hook (port, regs->eax); + }else if ( port ==0x42 || port ==0x43 || port ==0x61 )pv_pit_handler (port, regs->eax,1 );break ;
xen/include/asm-x86/acpi.h +2 -0
@@ -114,6 +114,8 @@ extern int acpi_strict;extern int acpi_disabled;extern int acpi_ht;extern int acpi_pci_disabled; +extern u32 acpi_smi_cmd; +extern u8 acpi_enable_value, acpi_disable_value;static inline void disable_acpi (void ) { acpi_disabled =1 ;
xen/include/asm-x86/io.h +2 -0
@@ -50,4 +50,6 @@ __OUT(b,"b",char) __OUT(w,"w",short) __OUT(l,,int) +extern void (*pv_post_outb_hook)(unsigned int port,u8 value); +#endif