From: Rik van Riel <riel@redhat.com> Date: Thu, 11 Sep 2008 01:11:18 -0400 Subject: [xen] cpufreq: fix Nehalem/Supermicro systems Message-id: 20080911011118.3824d1a0@riellaptop.surriel.com O-Subject: [PATCH 5.3 v2] fix xen cpufreq on Nehalem/Supermicro systems Bugzilla: 458894 RH-Acked-by: Chris Lalancette <clalance@redhat.com> RH-Acked-by: Don Dutile <ddutile@redhat.com> RH-Acked-by: Bill Burns <bburns@redhat.com> On Thu, 11 Sep 2008 00:26:47 -0400 Rik van Riel <riel@redhat.com> wrote: (lets try this again - now with the backported patch and not the upstream changeset that does not apply) This seemingly unrelated kernel-xen changeset resolves the ACPI confusion that stopped cpu frequency scaling code from working on the Intel Nehalem CPUs on Supermicro mainboards. Fixes bug 458894 # HG changeset patch # User Keir Fraser <keir.fraser@citrix.com> # Date 1204715381 0 # Node ID 26e1e96bd46a53991e216271d077aa6fb20ea218 # Parent 1cf7ba68d855aa86b1c54c34c03fc62571eb5c94 x86 xen: New vcpu_op call to get physical CPU identity. Some AMD machines have APIC IDs that not equal to CPU IDs. In the default Xen configuration, ACPI calls on these machines can get confused. This shows up most noticeably when running AMD PowerNow!. The only solution is for dom0 to get the hypervisor's cpuid to apicid table when needed (ie, when dom0 vcpus are pinned). Add a vcpu op to Xen to allow dom0 to query the hypervisor for architecture dependent physical cpu information if dom0 vcpus are pinned. Signed-off-by: Mark Langsdorf <mark.langsdorf@amd.com> Signed-off-by: Keir Fraser <keir.fraser@citrix.com> diff --git a/drivers/xen/core/smpboot.c b/drivers/xen/core/smpboot.c index 5f43010..d2d1182 100644 --- a/drivers/xen/core/smpboot.c +++ b/drivers/xen/core/smpboot.c @@ -249,17 +249,28 @@ void __init smp_prepare_cpus(unsigned int max_cpus) { int cpu; struct task_struct *idle; + int apicid, acpiid; + struct vcpu_get_physid cpu_id; #ifdef __x86_64__ struct desc_ptr *gdt_descr; #else struct Xgt_desc_struct *gdt_descr; #endif - boot_cpu_data.apicid = 0; + apicid = 0; + if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, 0, &cpu_id) == 0) { + apicid = xen_vcpu_physid_to_x86_apicid(cpu_id.phys_id); + acpiid = xen_vcpu_physid_to_x86_acpiid(cpu_id.phys_id); +#ifdef CONFIG_ACPI + if (acpiid != 0xff) + x86_acpiid_to_apicid[acpiid] = apicid; +#endif + } + boot_cpu_data.apicid = apicid; cpu_data[0] = boot_cpu_data; - cpu_2_logical_apicid[0] = 0; - x86_cpu_to_apicid[0] = 0; + cpu_2_logical_apicid[0] = apicid; + x86_cpu_to_apicid[0] = apicid; current_thread_info()->cpu = 0; @@ -303,11 +314,20 @@ void __init smp_prepare_cpus(unsigned int max_cpus) (void *)gdt_descr->address, XENFEAT_writable_descriptor_tables); + apicid = cpu; + if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, cpu, &cpu_id) == 0) { + apicid = xen_vcpu_physid_to_x86_apicid(cpu_id.phys_id); + acpiid = xen_vcpu_physid_to_x86_acpiid(cpu_id.phys_id); +#ifdef CONFIG_ACPI + if (acpiid != 0xff) + x86_acpiid_to_apicid[acpiid] = apicid; +#endif + } cpu_data[cpu] = boot_cpu_data; - cpu_data[cpu].apicid = cpu; + cpu_data[cpu].apicid = apicid; - cpu_2_logical_apicid[cpu] = cpu; - x86_cpu_to_apicid[cpu] = cpu; + cpu_2_logical_apicid[cpu] = apicid; + x86_cpu_to_apicid[cpu] = apicid; idle = fork_idle(cpu); if (IS_ERR(idle)) diff --git a/include/xen/interface/vcpu.h b/include/xen/interface/vcpu.h index 377defe..eb8b5a1 100644 --- a/include/xen/interface/vcpu.h +++ b/include/xen/interface/vcpu.h @@ -108,6 +108,24 @@ struct vcpu_register_runstate_memory_area { }; typedef struct vcpu_register_runstate_memory_area vcpu_register_runstate_memory_area_t; +#define VCPUOP_register_vcpu_info 10 /* arg == vcpu_register_vcpu_info_t */ + +/* + * Get the physical ID information for a pinned vcpu's underlying physical + * processor. The physical ID informmation is architecture-specific. + * On x86: id[7:0]=apic_id, id[15:8]=acpi_id, id[63:16]=mbz, + * and an unavailable identifier is returned as 0xff. + * This command returns -EINVAL if it is not a valid operation for this VCPU. + */ +#define VCPUOP_get_physid 12 /* arg == vcpu_get_physid_t */ +struct vcpu_get_physid { + uint64_t phys_id; +}; +typedef struct vcpu_get_physid vcpu_get_physid_t; +DEFINE_XEN_GUEST_HANDLE(vcpu_get_physid_t); +#define xen_vcpu_physid_to_x86_apicid(physid) ((uint8_t)((physid)>>0)) +#define xen_vcpu_physid_to_x86_acpiid(physid) ((uint8_t)((physid)>>8)) + #endif /* __XEN_PUBLIC_VCPU_H__ */ /*