From: "Siddha, Suresh B" <suresh.b.siddha@intel.com>

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 <suresh.b.siddha@intel.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 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
 
_