diff options
| author | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-05-02 15:04:51 -0400 |
|---|---|---|
| committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-05-07 10:18:47 -0400 |
| commit | 558daa289a402dbcce0c065c6ff3cc2e00ffeac8 (patch) | |
| tree | 7bb0cb50038d0d71786a4eabf37eae24fb0c2258 | |
| parent | a7a97c639478941102e33dcdd0ff6d4b70539533 (diff) | |
xen/apic: Return the APIC ID (and version) for CPU 0.
On x86_64 on AMD machines where the first APIC_ID is not zero, we get:
ACPI: LAPIC (acpi_id[0x01] lapic_id[0x10] enabled)
BIOS bug: APIC version is 0 for CPU 1/0x10, fixing up to 0x10
BIOS bug: APIC version mismatch, boot CPU: 0, CPU 1: version 10
which means that when the ACPI processor driver loads and
tries to parse the _Pxx states it fails to do as, as it
ends up calling acpi_get_cpuid which does this:
for_each_possible_cpu(i) {
if (cpu_physical_id(i) == apic_id)
return i;
}
And the bootup CPU, has not been found so it fails and returns -1
for the first CPU - which then subsequently in the loop that
"acpi_processor_get_info" does results in returning an error, which
means that "acpi_processor_add" failing and per_cpu(processor)
is never set (and is NULL).
That means that when xen-acpi-processor tries to load (much much
later on) and parse the P-states it gets -ENODEV from
acpi_processor_register_performance() (which tries to read
the per_cpu(processor)) and fails to parse the data.
Reported-by-and-Tested-by: Stefan Bader <stefan.bader@canonical.com>
Suggested-by: Boris Ostrovsky <boris.ostrovsky@amd.com>
[v2: Bit-shift APIC ID by 24 bits]
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
| -rw-r--r-- | arch/x86/xen/enlighten.c | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index a8f8844b8d32..4f437dedbdf5 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c | |||
| @@ -809,9 +809,40 @@ static void xen_io_delay(void) | |||
| 809 | } | 809 | } |
| 810 | 810 | ||
| 811 | #ifdef CONFIG_X86_LOCAL_APIC | 811 | #ifdef CONFIG_X86_LOCAL_APIC |
| 812 | static unsigned long xen_set_apic_id(unsigned int x) | ||
| 813 | { | ||
| 814 | WARN_ON(1); | ||
| 815 | return x; | ||
| 816 | } | ||
| 817 | static unsigned int xen_get_apic_id(unsigned long x) | ||
| 818 | { | ||
| 819 | return ((x)>>24) & 0xFFu; | ||
| 820 | } | ||
| 812 | static u32 xen_apic_read(u32 reg) | 821 | static u32 xen_apic_read(u32 reg) |
| 813 | { | 822 | { |
| 814 | return 0; | 823 | struct xen_platform_op op = { |
| 824 | .cmd = XENPF_get_cpuinfo, | ||
| 825 | .interface_version = XENPF_INTERFACE_VERSION, | ||
| 826 | .u.pcpu_info.xen_cpuid = 0, | ||
| 827 | }; | ||
| 828 | int ret = 0; | ||
| 829 | |||
| 830 | /* Shouldn't need this as APIC is turned off for PV, and we only | ||
| 831 | * get called on the bootup processor. But just in case. */ | ||
| 832 | if (!xen_initial_domain() || smp_processor_id()) | ||
| 833 | return 0; | ||
| 834 | |||
| 835 | if (reg == APIC_LVR) | ||
| 836 | return 0x10; | ||
| 837 | |||
| 838 | if (reg != APIC_ID) | ||
| 839 | return 0; | ||
| 840 | |||
| 841 | ret = HYPERVISOR_dom0_op(&op); | ||
| 842 | if (ret) | ||
| 843 | return 0; | ||
| 844 | |||
| 845 | return op.u.pcpu_info.apic_id << 24; | ||
| 815 | } | 846 | } |
| 816 | 847 | ||
| 817 | static void xen_apic_write(u32 reg, u32 val) | 848 | static void xen_apic_write(u32 reg, u32 val) |
| @@ -849,6 +880,8 @@ static void set_xen_basic_apic_ops(void) | |||
| 849 | apic->icr_write = xen_apic_icr_write; | 880 | apic->icr_write = xen_apic_icr_write; |
| 850 | apic->wait_icr_idle = xen_apic_wait_icr_idle; | 881 | apic->wait_icr_idle = xen_apic_wait_icr_idle; |
| 851 | apic->safe_wait_icr_idle = xen_safe_apic_wait_icr_idle; | 882 | apic->safe_wait_icr_idle = xen_safe_apic_wait_icr_idle; |
| 883 | apic->set_apic_id = xen_set_apic_id; | ||
| 884 | apic->get_apic_id = xen_get_apic_id; | ||
| 852 | } | 885 | } |
| 853 | 886 | ||
| 854 | #endif | 887 | #endif |
