x2apic: use cpuid vector 0xb when available for detecting cpu topology
PATCH 1/2 x2apic: use cpuid vector 0xb when available for detecting cpu topology
cpuid leaf 0xb provides extended topology enumeration. This interface provides the 32-bit x2APIC id of the logical processor and it also provides a new mechanism to detect SMT and core siblings (which provides increased addressability).
---
arch/x86/kernel/cpu/addon_cpuid_features.c +86 -0
@@ -7,6 +7,8 @@#include <asm/pat.h> #include <asm/processor.h> +#include <mach_apic.h> +struct cpuid_bit {u16 feature;u8 reg;
@@ -48,6 +50,90 @@ } } +/* leaf 0xb SMT level */ +#define SMT_LEVEL 0 + +/* leaf 0xb sub-leaf types */ +#define INVALID_TYPE 0 +#define SMT_TYPE 1 +#define CORE_TYPE 2 + +#define LEAFB_SUBTYPE (ecx) (((ecx) >> 8) & 0xff) +#define BITS_SHIFT_NEXT_LEVEL (eax) ((eax) & 0x1f) +#define LEVEL_MAX_SIBLINGS (ebx) ((ebx) & 0xffff) + +/* +* Check for extended topology enumeration cpuid leaf 0xb and if it +* exists, use it for populating initial_apicid and cpu topology +* detection. +*/ +void __cpuinit detect_extended_topology (struct cpuinfo_x86 *c) +{ +unsigned int eax, ebx, ecx, edx, sub_index; +unsigned int ht_mask_width, core_plus_mask_width; +unsigned int core_select_mask, core_level_siblings; + +if (c->cpuid_level <0xb ) +return ; + +cpuid_count (0xb ,SMT_LEVEL , &eax, &ebx, &ecx, &edx); + +/* +* check if the cpuid leaf 0xb is actually implemented. +*/ +if (ebx ==0 || (LEAFB_SUBTYPE (ecx) !=SMT_TYPE )) +return ; + +set_cpu_cap (c,X86_FEATURE_XTOPOLOGY ); + +/* +* initial apic id, which also represents 32-bit extended x2apic id. +*/ + c->initial_apicid = edx; + +/* +* Populate HT related information from sub-leaf level 0. +*/ + core_level_siblings = smp_num_siblings =LEVEL_MAX_SIBLINGS (ebx); + core_plus_mask_width = ht_mask_width =BITS_SHIFT_NEXT_LEVEL (eax); + + sub_index =1 ; +do { +cpuid_count (0xb , sub_index, &eax, &ebx, &ecx, &edx); + +/* +* Check for the Core type in the implemented sub leaves. +*/ +if (LEAFB_SUBTYPE (ecx) ==CORE_TYPE ) { + core_level_siblings =LEVEL_MAX_SIBLINGS (ebx); + core_plus_mask_width =BITS_SHIFT_NEXT_LEVEL (eax); +break ; + } + + sub_index++; + }while (LEAFB_SUBTYPE (ecx) !=INVALID_TYPE ); + + core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width; + +#ifdef CONFIG_X86_32 + c->cpu_core_id =phys_pkg_id (c->initial_apicid, ht_mask_width) + & core_select_mask; + c->phys_proc_id =phys_pkg_id (c->initial_apicid, core_plus_mask_width); +#else + c->cpu_core_id =phys_pkg_id (ht_mask_width) & core_select_mask; + c->phys_proc_id =phys_pkg_id (core_plus_mask_width); +#endif + c->x86_max_cores = (core_level_siblings / smp_num_siblings); + + +printk (KERN_INFO "CPU: Physical Processor ID: %d\n" , + c->phys_proc_id); +if (c->x86_max_cores >1 ) +printk (KERN_INFO "CPU: Processor Core ID: %d\n" , + c->cpu_core_id); +return ; +} +#ifdef CONFIG_X86_PAT void __cpuinit validate_pat_support (struct cpuinfo_x86 *c) {
arch/x86/kernel/cpu/common_64.c +3 -0
@@ -127,6 +127,9 @@u32 eax, ebx, ecx, edx;int index_msb, core_bits; +if (cpu_has (c,X86_FEATURE_XTOPOLOGY )) +return ; +cpuid (1 , &eax, &ebx, &ecx, &edx);
arch/x86/kernel/cpu/intel_64.c +4 -1
@@ -80,7 +80,10 @@if (c->x86 ==6 )set_cpu_cap (c,X86_FEATURE_REP_GOOD );set_cpu_cap (c,X86_FEATURE_LFENCE_RDTSC ); - c->x86_max_cores =intel_num_cpu_cores (c); + +detect_extended_topology (c); +if (!cpu_has (c,X86_FEATURE_XTOPOLOGY )) + c->x86_max_cores =intel_num_cpu_cores (c);srat_detect_node (); }
include/asm-x86/cpufeature.h +1 -0
@@ -80,6 +80,7 @@#define X86_FEATURE_MFENCE_RDTSC (3*32+17)/* Mfence synchronizes RDTSC */ #define X86_FEATURE_LFENCE_RDTSC (3*32+18)/* Lfence synchronizes RDTSC */ #define X86_FEATURE_11AP (3*32+19)/* Bad local APIC aka 11AP */ +#define X86_FEATURE_XTOPOLOGY (3*32+20)/* cpu topology enum extensions */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ #define X86_FEATURE_XMM3 (4*32+ 0)/* Streaming SIMD Extensions-3 */
include/asm-x86/processor.h +1 -0
@@ -166,6 +166,7 @@extern unsigned int init_intel_cacheinfo (struct cpuinfo_x86 *c);extern unsigned short num_cache_leaves; +extern void detect_extended_topology (struct cpuinfo_x86 *c);#if defined(CONFIG_X86_HT ) || defined(CONFIG_X86_64 )extern void detect_ht (struct cpuinfo_x86 *c);#else
arch/x86/kernel/cpu/intel.c +9 -2
@@ -183,9 +183,16 @@if (p)strcpy (c->x86_model_id, p); - c->x86_max_cores =num_cpu_cores (c); +detect_extended_topology (c); -detect_ht (c); +if (!cpu_has (c,X86_FEATURE_XTOPOLOGY )) { +/* +* let's use the legacy cpuid vector 0x1 and 0x4 for topology +* detection. +*/ + c->x86_max_cores =num_cpu_cores (c); +detect_ht (c); + }/* Work around errata */ Intel_errata_workarounds (c);
PATCH 2/2 x2apic: use x2apic id reported by cpuid during topology discovery
use x2apic id reported by cpuid during topology discovery, instead of the apic id configured in the APIC. For most of the systems, x2apic id reported by cpuid leaf 0xb will be same as the physical apic id reported by the APIC_ID register of the APIC. We follow the suggested guidelines and use the apic id reported by the cpuid.
No change to non-generic UV platforms, will use the apic id reported in the APIC_ID register as the cpuid reported apic id's may not be unique.
---
arch/x86/kernel/genx2apic_cluster.c +1 -6
@@ -120,14 +120,9 @@return x; } -static unsigned int x2apic_read_id (void ) -{ -return apic_read (APIC_ID ); -} -static unsigned int phys_pkg_id (int index_msb) { -return x2apic_read_id () >> index_msb; +return current_cpu_data.initial_apicid >> index_msb; }static void x2apic_send_IPI_self (int vector)
arch/x86/kernel/genx2apic_phys.c +1 -6
@@ -118,14 +118,9 @@return x; } -static unsigned int x2apic_read_id (void ) -{ -return apic_read (APIC_ID ); -} -static unsigned int phys_pkg_id (int index_msb) { -return x2apic_read_id () >> index_msb; +return current_cpu_data.initial_apicid >> index_msb; }void x2apic_send_IPI_self (int vector)
Ingo Molnar
AppliedRe: [patch 2/2] x2apic: use x2apic id reported by cpuid during topology discovery
Quoted 10 lines · Suresh Siddha
use x2apic id reported by cpuid during topology discovery, instead of the apic id configured in the APIC. For most of the systems, x2apic id reported by cpuid leaf
0xbwill be same as the physical apic id reported by theAPIC_IDregister of the APIC. We follow the suggested guidelines and use the apic id reported by the cpuid.No change to non-generic UV platforms, will use the apic id reported in the
APIC_IDregister as the cpuid reported apic id's may not be unique.Signed-off-by Suresh Siddha <[email protected]>
applied both fixes to tip/x86/x2apic - thanks Suresh!
Ingo