From: "Siddha, Suresh B" Appended patch adds the support for Intel dual-core detection and displaying the core related information in /proc/cpuinfo. It adds two new fields "core id" and "cpu cores" to x86 /proc/cpuinfo and the "core id" field for x86_64("cpu cores" field is already present in x86_64). Number of processor cores in a die is detected using cpuid(4) and this is documented in IA-32 Intel Architecture Software Developer's Manual (vol 2a) (http://developer.intel.com/design/pentium4/manuals/index_new.htm#sdm_vol2a) This patch also adds cpu_core_map similar to cpu_sibling_map. Signed-off-by: Suresh Siddha Signed-off-by: Andrew Morton --- 25-akpm/arch/i386/kernel/cpu/amd.c | 13 +++--- 25-akpm/arch/i386/kernel/cpu/common.c | 28 ++++++++++---- 25-akpm/arch/i386/kernel/cpu/intel.c | 23 ++++++++++++ 25-akpm/arch/i386/kernel/cpu/proc.c | 8 +++- 25-akpm/arch/i386/kernel/smpboot.c | 25 ++++++++++++- 25-akpm/arch/x86_64/kernel/setup.c | 64 ++++++++++++++++++++++++++-------- 25-akpm/arch/x86_64/kernel/smpboot.c | 22 ++++++++++- 25-akpm/include/asm-i386/processor.h | 1 25-akpm/include/asm-i386/smp.h | 1 25-akpm/include/asm-x86_64/smp.h | 2 + 10 files changed, 152 insertions(+), 35 deletions(-) diff -puN arch/i386/kernel/cpu/amd.c~x86-x86_64-intel-dual-core-detection arch/i386/kernel/cpu/amd.c --- 25/arch/i386/kernel/cpu/amd.c~x86-x86_64-intel-dual-core-detection 2005-03-15 23:20:11.000000000 -0800 +++ 25-akpm/arch/i386/kernel/cpu/amd.c 2005-03-15 23:20:11.000000000 -0800 @@ -188,6 +188,13 @@ static void __init init_amd(struct cpuin } display_cacheinfo(c); + + if (cpuid_eax(0x80000000) >= 0x80000008) { + c->x86_num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1; + if (c->x86_num_cores & (c->x86_num_cores - 1)) + c->x86_num_cores = 1; + } + detect_ht(c); #ifdef CONFIG_X86_HT @@ -199,12 +206,6 @@ static void __init init_amd(struct cpuin if (cpu_has(c, X86_FEATURE_CMP_LEGACY)) smp_num_siblings = 1; #endif - - if (cpuid_eax(0x80000000) >= 0x80000008) { - c->x86_num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1; - if (c->x86_num_cores & (c->x86_num_cores - 1)) - c->x86_num_cores = 1; - } } static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size) diff -puN arch/i386/kernel/cpu/common.c~x86-x86_64-intel-dual-core-detection arch/i386/kernel/cpu/common.c --- 25/arch/i386/kernel/cpu/common.c~x86-x86_64-intel-dual-core-detection 2005-03-15 23:20:11.000000000 -0800 +++ 25-akpm/arch/i386/kernel/cpu/common.c 2005-03-15 23:20:11.000000000 -0800 @@ -435,7 +435,7 @@ void __init identify_cpu(struct cpuinfo_ void __init detect_ht(struct cpuinfo_x86 *c) { u32 eax, ebx, ecx, edx; - int index_lsb, index_msb, tmp; + int index_msb, tmp; int cpu = smp_processor_id(); if (!cpu_has(c, X86_FEATURE_HT)) @@ -447,7 +447,6 @@ void __init detect_ht(struct cpuinfo_x86 if (smp_num_siblings == 1) { printk(KERN_INFO "CPU: Hyper-Threading is disabled\n"); } else if (smp_num_siblings > 1 ) { - index_lsb = 0; index_msb = 31; if (smp_num_siblings > NR_CPUS) { @@ -456,21 +455,34 @@ void __init detect_ht(struct cpuinfo_x86 return; } tmp = smp_num_siblings; - while ((tmp & 1) == 0) { - tmp >>=1 ; - index_lsb++; - } - tmp = smp_num_siblings; while ((tmp & 0x80000000 ) == 0) { tmp <<=1 ; index_msb--; } - if (index_lsb != index_msb ) + if (smp_num_siblings & (smp_num_siblings - 1)) index_msb++; phys_proc_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb); printk(KERN_INFO "CPU: Physical Processor ID: %d\n", phys_proc_id[cpu]); + + smp_num_siblings = smp_num_siblings / c->x86_num_cores; + + tmp = smp_num_siblings; + index_msb = 31; + while ((tmp & 0x80000000) == 0) { + tmp <<= 1; + index_msb--; + } + + if (smp_num_siblings & (smp_num_siblings - 1)) + index_msb++; + + cpu_core_id[cpu] = phys_pkg_id((ebx >> 24) & 0xFF, index_msb); + + if (c->x86_num_cores > 1) + printk(KERN_INFO "CPU: Processor Core ID: %d\n", + cpu_core_id[cpu]); } } #endif diff -puN arch/i386/kernel/cpu/intel.c~x86-x86_64-intel-dual-core-detection arch/i386/kernel/cpu/intel.c --- 25/arch/i386/kernel/cpu/intel.c~x86-x86_64-intel-dual-core-detection 2005-03-15 23:20:11.000000000 -0800 +++ 25-akpm/arch/i386/kernel/cpu/intel.c 2005-03-15 23:20:11.000000000 -0800 @@ -77,6 +77,27 @@ static void __init Intel_errata_workarou } +/* + * find out the number of processor cores on the die + */ +static int __init num_cpu_cores(struct cpuinfo_x86 *c) +{ + unsigned int eax; + + if (c->cpuid_level < 4) + return 1; + + __asm__("cpuid" + : "=a" (eax) + : "0" (4), "c" (0) + : "bx", "dx"); + + if (eax & 0x1f) + return ((eax >> 26) + 1); + else + return 1; +} + static void __init init_intel(struct cpuinfo_x86 *c) { unsigned int l2 = 0; @@ -139,6 +160,8 @@ static void __init init_intel(struct cpu if ( p ) strcpy(c->x86_model_id, p); + c->x86_num_cores = num_cpu_cores(c); + detect_ht(c); /* Work around errata */ diff -puN arch/i386/kernel/cpu/proc.c~x86-x86_64-intel-dual-core-detection arch/i386/kernel/cpu/proc.c --- 25/arch/i386/kernel/cpu/proc.c~x86-x86_64-intel-dual-core-detection 2005-03-15 23:20:11.000000000 -0800 +++ 25-akpm/arch/i386/kernel/cpu/proc.c 2005-03-15 23:20:11.000000000 -0800 @@ -94,8 +94,12 @@ static int show_cpuinfo(struct seq_file if (c->x86_cache_size >= 0) seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); #ifdef CONFIG_X86_HT - seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]); - seq_printf(m, "siblings\t: %d\n", c->x86_num_cores * smp_num_siblings); + if (smp_num_siblings > 1 || c->x86_num_cores > 1) { + seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]); + seq_printf(m, "siblings\t: %d\n", c->x86_num_cores * smp_num_siblings); + seq_printf(m, "core id\t\t: %d\n", cpu_core_id[n]); + seq_printf(m, "cpu cores\t: %d\n", c->x86_num_cores); + } #endif /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ diff -puN arch/i386/kernel/smpboot.c~x86-x86_64-intel-dual-core-detection arch/i386/kernel/smpboot.c --- 25/arch/i386/kernel/smpboot.c~x86-x86_64-intel-dual-core-detection 2005-03-15 23:20:11.000000000 -0800 +++ 25-akpm/arch/i386/kernel/smpboot.c 2005-03-15 23:20:11.000000000 -0800 @@ -62,6 +62,8 @@ static int __initdata smp_b_stepping; int smp_num_siblings = 1; int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ EXPORT_SYMBOL(phys_proc_id); +int cpu_core_id[NR_CPUS]; /* Core ID of each logical CPU */ +EXPORT_SYMBOL(cpu_core_id); /* bitmap of online cpus */ cpumask_t cpu_online_map; @@ -885,6 +887,7 @@ static int boot_cpu_logical_apicid; void *xquad_portio; cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; +cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; static void __init smp_boot_cpus(unsigned int max_cpus) { @@ -907,6 +910,9 @@ static void __init smp_boot_cpus(unsigne cpus_clear(cpu_sibling_map[0]); cpu_set(0, cpu_sibling_map[0]); + cpus_clear(cpu_core_map[0]); + cpu_set(0, cpu_core_map[0]); + /* * If we couldn't find an SMP configuration at boot time, * get out of here now! @@ -1035,10 +1041,13 @@ static void __init smp_boot_cpus(unsigne * construct cpu_sibling_map[], so that we can tell sibling CPUs * efficiently. */ - for (cpu = 0; cpu < NR_CPUS; cpu++) + for (cpu = 0; cpu < NR_CPUS; cpu++) { cpus_clear(cpu_sibling_map[cpu]); + cpus_clear(cpu_core_map[cpu]); + } for (cpu = 0; cpu < NR_CPUS; cpu++) { + struct cpuinfo_x86 *c = cpu_data + cpu; int siblings = 0; int i; if (!cpu_isset(cpu, cpu_callout_map)) @@ -1048,7 +1057,7 @@ static void __init smp_boot_cpus(unsigne for (i = 0; i < NR_CPUS; i++) { if (!cpu_isset(i, cpu_callout_map)) continue; - if (phys_proc_id[cpu] == phys_proc_id[i]) { + if (cpu_core_id[cpu] == cpu_core_id[i]) { siblings++; cpu_set(i, cpu_sibling_map[cpu]); } @@ -1060,6 +1069,18 @@ static void __init smp_boot_cpus(unsigne if (siblings != smp_num_siblings) printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings); + + if (c->x86_num_cores > 1) { + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_isset(i, cpu_callout_map)) + continue; + if (phys_proc_id[cpu] == phys_proc_id[i]) { + cpu_set(i, cpu_core_map[cpu]); + } + } + } else { + cpu_core_map[cpu] = cpu_sibling_map[cpu]; + } } if (nmi_watchdog == NMI_LOCAL_APIC) diff -puN arch/x86_64/kernel/setup.c~x86-x86_64-intel-dual-core-detection arch/x86_64/kernel/setup.c --- 25/arch/x86_64/kernel/setup.c~x86-x86_64-intel-dual-core-detection 2005-03-15 23:20:11.000000000 -0800 +++ 25-akpm/arch/x86_64/kernel/setup.c 2005-03-15 23:20:11.000000000 -0800 @@ -784,7 +784,7 @@ static void __init detect_ht(struct cpui { #ifdef CONFIG_SMP u32 eax, ebx, ecx, edx; - int index_lsb, index_msb, tmp; + int index_msb, tmp; int cpu = smp_processor_id(); if (!cpu_has(c, X86_FEATURE_HT)) @@ -796,7 +796,6 @@ static void __init detect_ht(struct cpui if (smp_num_siblings == 1) { printk(KERN_INFO "CPU: Hyper-Threading is disabled\n"); } else if (smp_num_siblings > 1) { - index_lsb = 0; index_msb = 31; /* * At this point we only support two siblings per @@ -808,21 +807,33 @@ static void __init detect_ht(struct cpui return; } tmp = smp_num_siblings; - while ((tmp & 1) == 0) { - tmp >>=1 ; - index_lsb++; - } - tmp = smp_num_siblings; while ((tmp & 0x80000000 ) == 0) { tmp <<=1 ; index_msb--; } - if (index_lsb != index_msb ) + if (smp_num_siblings & (smp_num_siblings - 1)) index_msb++; phys_proc_id[cpu] = phys_pkg_id(index_msb); printk(KERN_INFO "CPU: Physical Processor ID: %d\n", phys_proc_id[cpu]); + + smp_num_siblings = smp_num_siblings / c->x86_num_cores; + + tmp = smp_num_siblings; + index_msb = 31; + while ((tmp & 0x80000000) == 0) { + tmp <<= 1; + index_msb--; + } + if (smp_num_siblings & (smp_num_siblings - 1)) + index_msb++; + + cpu_core_id[cpu] = phys_pkg_id(index_msb); + + if (c->x86_num_cores > 1) + printk(KERN_INFO "CPU: Processor Core ID: %d\n", + cpu_core_id[cpu]); } #endif } @@ -839,7 +850,28 @@ static void __init sched_cmp_hack(struct smp_num_siblings = 1; #endif } - + +/* + * find out the number of processor cores on the die + */ +static int __init num_cpu_cores(struct cpuinfo_x86 *c) +{ + unsigned int eax; + + if (c->cpuid_level < 4) + return 1; + + __asm__("cpuid" + : "=a" (eax) + : "0" (4), "c" (0) + : "bx", "dx"); + + if (eax & 0x1f) + return ((eax >> 26) + 1); + else + return 1; +} + static void __init init_intel(struct cpuinfo_x86 *c) { /* Cache sizes */ @@ -855,6 +887,8 @@ static void __init init_intel(struct cpu if (c->x86 == 15) c->x86_cache_alignment = c->x86_clflush_size * 2; + + c->x86_num_cores = num_cpu_cores(c); } void __init get_cpu_vendor(struct cpuinfo_x86 *c) @@ -1111,8 +1145,12 @@ static int show_cpuinfo(struct seq_file seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); #ifdef CONFIG_SMP - seq_printf(m, "physical id\t: %d\n", phys_proc_id[c - cpu_data]); - seq_printf(m, "siblings\t: %d\n", c->x86_num_cores * smp_num_siblings); + if (smp_num_siblings > 1 || c->x86_num_cores > 1) { + seq_printf(m, "physical id\t: %d\n", phys_proc_id[c - cpu_data]); + seq_printf(m, "siblings\t: %d\n", c->x86_num_cores * smp_num_siblings); + seq_printf(m, "core id\t\t: %d\n", cpu_core_id[c - cpu_data]); + seq_printf(m, "cpu cores\t: %d\n", c->x86_num_cores); + } #endif seq_printf(m, @@ -1154,10 +1192,6 @@ static int show_cpuinfo(struct seq_file seq_printf(m, " [%d]", i); } } - seq_printf(m, "\n"); - - if (c->x86_num_cores > 1) - seq_printf(m, "cpu cores\t: %d\n", c->x86_num_cores); seq_printf(m, "\n\n"); diff -puN arch/x86_64/kernel/smpboot.c~x86-x86_64-intel-dual-core-detection arch/x86_64/kernel/smpboot.c --- 25/arch/x86_64/kernel/smpboot.c~x86-x86_64-intel-dual-core-detection 2005-03-15 23:20:11.000000000 -0800 +++ 25-akpm/arch/x86_64/kernel/smpboot.c 2005-03-15 23:20:11.000000000 -0800 @@ -58,7 +58,10 @@ int smp_num_siblings = 1; /* Package ID of each logical CPU */ u8 phys_proc_id[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; +/* Core ID of each logical CPU */ +u8 cpu_core_id[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; EXPORT_SYMBOL(phys_proc_id); +EXPORT_SYMBOL(cpu_core_id); /* Bitmask of currently online CPUs */ cpumask_t cpu_online_map; @@ -71,6 +74,7 @@ static cpumask_t smp_commenced_mask; struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned; +cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned; /* * Trampoline 80x86 program as an array. @@ -836,10 +840,13 @@ static void __init smp_boot_cpus(unsigne * Construct cpu_sibling_map[], so that we can tell the * sibling CPU efficiently. */ - for (cpu = 0; cpu < NR_CPUS; cpu++) + for (cpu = 0; cpu < NR_CPUS; cpu++) { cpus_clear(cpu_sibling_map[cpu]); + cpus_clear(cpu_core_map[cpu]); + } for (cpu = 0; cpu < NR_CPUS; cpu++) { + struct cpuinfo_x86 *c = cpu_data + cpu; int siblings = 0; int i; if (!cpu_isset(cpu, cpu_callout_map)) @@ -849,7 +856,7 @@ static void __init smp_boot_cpus(unsigne for (i = 0; i < NR_CPUS; i++) { if (!cpu_isset(i, cpu_callout_map)) continue; - if (phys_proc_id[cpu] == phys_proc_id[i]) { + if (cpu_core_id[cpu] == cpu_core_id[i]) { siblings++; cpu_set(i, cpu_sibling_map[cpu]); } @@ -865,6 +872,17 @@ static void __init smp_boot_cpus(unsigne siblings, cpu, smp_num_siblings); smp_num_siblings = siblings; } + + if (c->x86_num_cores > 1) { + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_isset(i, cpu_callout_map)) + continue; + if (phys_proc_id[cpu] == phys_proc_id[i]) { + cpu_set(i, cpu_core_map[cpu]); + } + } + } else + cpu_core_map[cpu] = cpu_sibling_map[cpu]; } Dprintk("Boot done.\n"); diff -puN include/asm-i386/processor.h~x86-x86_64-intel-dual-core-detection include/asm-i386/processor.h --- 25/include/asm-i386/processor.h~x86-x86_64-intel-dual-core-detection 2005-03-15 23:20:11.000000000 -0800 +++ 25-akpm/include/asm-i386/processor.h 2005-03-15 23:20:11.000000000 -0800 @@ -98,6 +98,7 @@ extern struct cpuinfo_x86 cpu_data[]; #endif extern int phys_proc_id[NR_CPUS]; +extern int cpu_core_id[NR_CPUS]; extern char ignore_fpu_irq; extern void identify_cpu(struct cpuinfo_x86 *); diff -puN include/asm-i386/smp.h~x86-x86_64-intel-dual-core-detection include/asm-i386/smp.h --- 25/include/asm-i386/smp.h~x86-x86_64-intel-dual-core-detection 2005-03-15 23:20:11.000000000 -0800 +++ 25-akpm/include/asm-i386/smp.h 2005-03-15 23:20:11.000000000 -0800 @@ -35,6 +35,7 @@ extern void smp_alloc_memory(void); extern int pic_mode; extern int smp_num_siblings; extern cpumask_t cpu_sibling_map[]; +extern cpumask_t cpu_core_map[]; extern void smp_flush_tlb(void); extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); diff -puN include/asm-x86_64/smp.h~x86-x86_64-intel-dual-core-detection include/asm-x86_64/smp.h --- 25/include/asm-x86_64/smp.h~x86-x86_64-intel-dual-core-detection 2005-03-15 23:20:11.000000000 -0800 +++ 25-akpm/include/asm-x86_64/smp.h 2005-03-15 23:20:11.000000000 -0800 @@ -48,7 +48,9 @@ extern void (*mtrr_hook) (void); extern void zap_low_mappings(void); void smp_stop_cpu(void); extern cpumask_t cpu_sibling_map[NR_CPUS]; +extern cpumask_t cpu_core_map[NR_CPUS]; extern u8 phys_proc_id[NR_CPUS]; +extern u8 cpu_core_id[NR_CPUS]; #define SMP_TRAMPOLINE_BASE 0x6000 _