x86: Adapt CPU topology detection for AMD Magny-Cours
v6 cover x86: Adapt CPU topology detection for AMD Magny-Cours
Hi,
Another version of patches to fix topology issues for AMD multi-node processors. This time w/o introduction of new /sysfs attributes or additional log messages.
It is just the pure stuff that is needed to fix some oddities that occur when Linux is booted on Magny-Cours.
Please apply the patches. They should go into .32.
Users who are interested in which CPUs belong to the same internal node have to check shared_cpu_map of L3 cache (i.e. /sys/devices/system/cpu/cpuXY/cache/index3/shared_cpu_map or /sys/devices/system/cpu/cpuXY/cache/index3/shared_cpu_list)
Boris might be interested in cpuinfo_x86->cpu_node_id. I use it to store the entire NodeId of AMD CPUs. That should be convenient enough to find out the northbridge of a CPU in the EDAC driver.
The scheduler stuff is in flux in general and I don't expect that scheduler gets fixed for Magny-Cours with .32. So be aware that changing to power savings scheduling might bring down your multi-node processor system.
Regards,
Andreas
Signature · 5 lines
Operating | Advanced Micro Devices GmbH System | Karl-Hammerschmidt-Str. 34, 85609 Dornach b. München, Germany Research | Geschäftsführer: Andrew Bowd, Thomas M. McCoy, Giuliano Meroni Center | Sitz: Dornach, Gemeinde Aschheim, Landkreis München (OSRC) | Registergericht München, HRB Nr. 43632
PATCH v6 1/5 x86, smpboot: use zalloc_cpumask_var instead of alloc/clear
--- arch/x86/kernel/smpboot.c | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-)
arch/x86/kernel/smpboot.c +3 -6
@@ -1059,12 +1059,9 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)#endif current_thread_info ()->cpu =0 ;/* needed? */ for_each_possible_cpu (i) { -alloc_cpumask_var (&per_cpu (cpu_sibling_map, i),GFP_KERNEL ); -alloc_cpumask_var (&per_cpu (cpu_core_map, i),GFP_KERNEL ); -alloc_cpumask_var (&cpu_data (i).llc_shared_map,GFP_KERNEL ); -cpumask_clear (per_cpu (cpu_core_map, i)); -cpumask_clear (per_cpu (cpu_sibling_map, i)); -cpumask_clear (cpu_data (i).llc_shared_map); +zalloc_cpumask_var (&per_cpu (cpu_sibling_map, i),GFP_KERNEL ); +zalloc_cpumask_var (&per_cpu (cpu_core_map, i),GFP_KERNEL ); +zalloc_cpumask_var (&cpu_data (i).llc_shared_map,GFP_KERNEL ); }set_cpu_sibling_map (0 );
Signature · 1 line
1.6.4
PATCH v6 2/5 x86: Store CPU topology information for multi-node processors
In reply to Andreas HerrmannIntroduce cpu_node_map, i.e. map of CPUs on same internal node. CPUs with matching phys_proc_id and cpu_node_id belong to the same cpu_node.
--- arch/x86/include/asm/processor.h | 2 ++ arch/x86/include/asm/smp.h | 6 ++++++ arch/x86/kernel/smpboot.c | 12 ++++++++++++ 3 files changed, 20 insertions(+), 0 deletions(-)
arch/x86/include/asm/processor.h +2 -0
@@ -107,6 +107,8 @@ struct cpuinfo_x86 {u16 booted_cores;/* Physical processor id: */ u16 phys_proc_id; +/* Node id in case of multi-node processor: */ +u16 cpu_node_id;/* Core id: */ u16 cpu_core_id;/* Index into per_cpu list: */
arch/x86/include/asm/smp.h +6 -0
@@ -22,6 +22,7 @@ extern int smp_num_siblings;extern unsigned int num_processors;DECLARE_PER_CPU (cpumask_var_t, cpu_sibling_map); +DECLARE_PER_CPU (cpumask_var_t, cpu_node_map);DECLARE_PER_CPU (cpumask_var_t, cpu_core_map);DECLARE_PER_CPU (u16, cpu_llc_id);DECLARE_PER_CPU (int, cpu_number);
@@ -31,6 +32,11 @@ static inline struct cpumask *cpu_sibling_mask(int cpu)return per_cpu (cpu_sibling_map, cpu); } +static inline struct cpumask *cpu_node_mask (int cpu) +{ +return per_cpu (cpu_node_map, cpu); +} +static inline struct cpumask *cpu_core_mask (int cpu) {return per_cpu (cpu_core_map, cpu);
arch/x86/kernel/smpboot.c +12 -0
@@ -109,6 +109,10 @@ EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);DEFINE_PER_CPU (cpumask_var_t, cpu_core_map);EXPORT_PER_CPU_SYMBOL (cpu_core_map); +/* representing node silbings on multi-node CPU */ +DEFINE_PER_CPU (cpumask_var_t, cpu_node_map); +EXPORT_PER_CPU_SYMBOL (cpu_node_map); +/* Per CPU bogomips and other parameters */ DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);EXPORT_PER_CPU_SYMBOL (cpu_info);
@@ -403,6 +407,11 @@ void __cpuinit set_cpu_sibling_map(int cpu)cpumask_set_cpu (i, c->llc_shared_map);cpumask_set_cpu (cpu,cpu_data (i).llc_shared_map); } +if ((c->phys_proc_id ==cpu_data (i).phys_proc_id) && + (c->cpu_node_id ==cpu_data (i).cpu_node_id)) { +cpumask_set_cpu (i,cpu_node_mask (cpu)); +cpumask_set_cpu (cpu,cpu_node_mask (i)); + }if (c->phys_proc_id ==cpu_data (i).phys_proc_id) {cpumask_set_cpu (i,cpu_core_mask (cpu));cpumask_set_cpu (cpu,cpu_core_mask (i));
@@ -1062,6 +1071,7 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)zalloc_cpumask_var (&per_cpu (cpu_sibling_map, i),GFP_KERNEL );zalloc_cpumask_var (&per_cpu (cpu_core_map, i),GFP_KERNEL );zalloc_cpumask_var (&cpu_data (i).llc_shared_map,GFP_KERNEL ); +zalloc_cpumask_var (&per_cpu (cpu_node_map, i),GFP_KERNEL ); }set_cpu_sibling_map (0 );
@@ -1221,6 +1231,7 @@ static void remove_siblinginfo(int cpu)for_each_cpu (sibling,cpu_core_mask (cpu)) {cpumask_clear_cpu (cpu,cpu_core_mask (sibling)); +cpumask_clear_cpu (cpu,cpu_node_mask (sibling));/*/ * last thread sibling in this cpu core going down */
@@ -1233,6 +1244,7 @@ static void remove_siblinginfo(int cpu)cpumask_clear (cpu_sibling_mask (cpu));cpumask_clear (cpu_core_mask (cpu)); c->phys_proc_id =0 ; + c->cpu_node_id =0 ; c->cpu_core_id =0 ;cpumask_clear_cpu (cpu, cpu_sibling_setup_mask); }
Signature · 1 line
1.6.4
PATCH v6 3/5 x86: Fill cpu_node information for AMD Magny-Cours
In reply to Andreas Herrmann--- arch/x86/include/asm/cpufeature.h | 1 + arch/x86/kernel/cpu/amd.c | 68 +++++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 3 deletions(-)
arch/x86/include/asm/cpufeature.h +1 -0
@@ -95,6 +95,7 @@#define X86_FEATURE_NONSTOP_TSC (3*32+24)/* TSC does not stop in C states */ #define X86_FEATURE_CLFLUSH_MONITOR (3*32+25)/* "" clflush reqd with monitor */ #define X86_FEATURE_EXTD_APICID (3*32+26)/* has extended APICID (8 bits) */ +#define X86_FEATURE_AMD_DCM (3*32+27)/* multi-node processor */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ #define X86_FEATURE_XMM3 (4*32+ 0)/* "pni" SSE-3 */
arch/x86/kernel/cpu/amd.c +65 -3
86 lines not on this page · raw message
Signature · 1 line
1.6.4
PATCH v6 4/5 x86, cacheinfo: Fixup L3 cache information for AMD multi-node processors
In reply to Andreas HerrmannL3 cache size, associativity and shared_cpu information need to be adapted to show information for an internal node instead of the entire physical package.
--- arch/x86/kernel/cpu/intel_cacheinfo.c | 30 ++++++++++++++++++++---------- 1 files changed, 20 insertions(+), 10 deletions(-)
arch/x86/kernel/cpu/intel_cacheinfo.c +20 -10
@@ -241,7 +241,7 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,case 0 :if (!l1->val)return ; - assoc = l1->assoc; + assoc = assocs[l1->assoc]; line_size = l1->line_size; lines_per_tag = l1->lines_per_tag; size_in_kb = l1->size_in_kb;
@@ -249,7 +249,7 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,case 2 :if (!l2.val)return ; - assoc = l2.assoc; + assoc = assocs[l2.assoc]; line_size = l2.line_size; lines_per_tag = l2.lines_per_tag;/* cpu_data has errata corrections for K7 applied */
@@ -258,10 +258,14 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,case 3 :if (!l3.val)return ; - assoc = l3.assoc; + assoc = assocs[l3.assoc]; line_size = l3.line_size; lines_per_tag = l3.lines_per_tag; size_in_kb = l3.size_encoded *512 ; +if (boot_cpu_has (X86_FEATURE_AMD_DCM )) { + size_in_kb = size_in_kb >>1 ; + assoc = assoc >>1 ; + }break ;default :return ;
@@ -270,18 +274,14 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax, eax->split.is_self_initializing =1 ; eax->split.type = types[leaf]; eax->split.level = levels[leaf]; -if (leaf ==3 ) - eax->split.num_threads_sharing = - current_cpu_data.x86_max_cores -1 ; -else - eax->split.num_threads_sharing =0 ; + eax->split.num_threads_sharing =0 ; eax->split.num_cores_on_die = current_cpu_data.x86_max_cores -1 ; -if (assoc ==0xf ) +if (assoc ==0xffff ) eax->split.is_fully_associative =1 ; ebx->split.coherency_line_size = line_size -1 ; - ebx->split.ways_of_associativity = assocs[assoc] -1 ; + ebx->split.ways_of_associativity = assoc -1 ; ebx->split.physical_line_partition = lines_per_tag -1 ; ecx->split.number_of_sets = (size_in_kb *1024 ) / line_size / (ebx->split.ways_of_associativity +1 ) -1 ;
@@ -523,6 +523,16 @@ static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)int index_msb, i;struct cpuinfo_x86 *c = &cpu_data (cpu); +if ((index ==3 ) && (c->x86_vendor ==X86_VENDOR_AMD )) { +for_each_online_cpu (i) { +if (!per_cpu (cpuid4_info, i)) +continue ; + this_leaf =CPUID4_INFO_IDX (i, index); +cpumask_copy (to_cpumask (this_leaf->shared_cpu_map), +cpu_node_mask (i)); + } +return ; + } this_leaf =CPUID4_INFO_IDX (cpu, index); num_threads_sharing =1 + this_leaf->eax.split.num_threads_sharing;
Signature · 1 line
1.6.4
PATCH v6 5/5 x86, mcheck: Make use of cpu_node_mask instead of cpu_core_mask
In reply to Andreas HerrmannThis fixes threshold_bank4 support on multi-node processors.
We need to create 2 sets of symlinks for sibling shared banks -- one set for each internal node, symlinks of each set should target the first core on same internal node.
Currently only one set is created where all symlinks are targeting the first core of the entire socket.
--- arch/x86/kernel/cpu/mcheck/mce_amd.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/cpu/mcheck/mce_amd.c +3 -3
@@ -494,7 +494,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)#ifdef CONFIG_SMP if (cpu_data (cpu).cpu_core_id && shared_bank[bank]) {/* symlink */ - i =cpumask_first (cpu_core_mask (cpu)); + i =cpumask_first (cpu_node_mask (cpu));/* first core not up yet */ if (cpu_data (i).cpu_core_id)
@@ -514,7 +514,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)if (err) goto out; -cpumask_copy (b->cpus,cpu_core_mask (cpu)); +cpumask_copy (b->cpus,cpu_node_mask (cpu));per_cpu (threshold_banks, cpu)[bank] = b; goto out;
@@ -539,7 +539,7 @@ static __cpuinit int threshold_create_bank(unsigned int cpu, unsigned int bank)#ifndef CONFIG_SMP cpumask_setall (b->cpus);#else -cpumask_copy (b->cpus,cpu_core_mask (cpu)); +cpumask_copy (b->cpus,cpu_node_mask (cpu));#endif per_cpu (threshold_banks, cpu)[bank] = b;
Signature · 1 line
1.6.4