]> xenbits.xensource.com Git - xen.git/commitdiff
x86: disable AMD's C1E mode.
authorKeir Fraser <keir@xensource.com>
Thu, 11 Oct 2007 12:27:38 +0000 (13:27 +0100)
committerKeir Fraser <keir@xensource.com>
Thu, 11 Oct 2007 12:27:38 +0000 (13:27 +0100)
In C1E the APIC timer stops ticking, which Xen cannot tolerate.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
xen/arch/x86/acpi/boot.c
xen/arch/x86/cpu/amd.c
xen/arch/x86/traps.c
xen/include/asm-x86/acpi.h
xen/include/asm-x86/io.h

index ba308687acb016cfd19451a45888a62ed4b01a3c..5973fd53eb3430148bc2c0cbaa5f02cfecf5df0a 100644 (file)
@@ -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(unsigned long phys, unsigned long size)
                       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;
 }
 
index 19a977cbefcee731b46beb6507ffb8477b1650a8..13fec06717dd5840032e41c53487704cfab9d401 100644 (file)
@@ -102,6 +102,29 @@ static void disable_c1_ramping(void)
 
 int force_mwait __cpuinitdata;
 
+static void disable_c1e(void *unused)
+{
+       u32 lo, hi;
+
+       /*
+        * Disable C1E mode, as the APIC timer stops in that mode.
+        * The MSR does not exist in all FamilyF CPUs (only Rev F and above),
+        * but we safely catch the #GP in that case.
+        */
+       if ((rdmsr_safe(MSR_K8_ENABLE_C1E, lo, hi) == 0) &&
+           (lo & (3u << 27)) &&
+           (wrmsr_safe(MSR_K8_ENABLE_C1E, lo & ~(3u << 27), 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)
+{
+       /* C1E is sometimes enabled during entry to ACPI mode. */
+       if ((port == acpi_smi_cmd) && (value == acpi_enable_value))
+               on_each_cpu(disable_c1e, NULL, 1, 1);
+}
+
 static void __init init_amd(struct cpuinfo_x86 *c)
 {
        u32 l, h;
@@ -282,6 +305,9 @@ static void __init init_amd(struct cpuinfo_x86 *c)
        case 0x10:
        case 0x11:
                set_bit(X86_FEATURE_K8, c->x86_capability);
+               disable_c1e(NULL);
+               if (acpi_smi_cmd && (acpi_enable_value | acpi_disable_value))
+                       pv_post_outb_hook = check_disable_c1e;
                break;
        case 6:
                set_bit(X86_FEATURE_K7, c->x86_capability);
@@ -335,6 +361,7 @@ static void __init init_amd(struct cpuinfo_x86 *c)
        }
 #endif
 
+       /* Pointless to use MWAIT on Family10 as it does not deep sleep. */
        if (c->x86 == 0x10 && !force_mwait)
                clear_bit(X86_FEATURE_MWAIT, c->x86_capability);
 
index 7e77d9e6c4383c1db5e5d9f83c6f5469e5120fe3..4d4fdffca74f0f65d08586533b622e5959fde65e 100644 (file)
@@ -1184,6 +1184,8 @@ void host_to_guest_gpr_switch(struct cpu_user_regs *)
 unsigned 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);                               \
@@ -1412,7 +1414,11 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
             {
             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;
@@ -1530,7 +1536,11 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
         {
         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;
index 872091f67b997e6e9a8f843cf111ab4d0e2d8c17..c8e0c6f46e52099ab0198f93a05df5bb6a78fa21 100644 (file)
@@ -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;
index 968e7d35ce4d4de32ca03c14d93b6bf0364e09f7..7179a9ee75acae9e3748e471bbc42ac3b0b67d96 100644 (file)
@@ -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