diff options
-rw-r--r-- | xen/arch/x86/cpu/amd.c | 29 | ||||
-rw-r--r-- | xen/arch/x86/cpu/common.c | 49 | ||||
-rw-r--r-- | xen/arch/x86/cpu/cpu.h | 1 | ||||
-rw-r--r-- | xen/arch/x86/cpu/intel.c | 23 | ||||
-rw-r--r-- | xen/arch/x86/dom0_ops.c | 4 | ||||
-rw-r--r-- | xen/arch/x86/setup.c | 1 | ||||
-rw-r--r-- | xen/arch/x86/smpboot.c | 32 | ||||
-rw-r--r-- | xen/common/dom0_ops.c | 4 | ||||
-rw-r--r-- | xen/include/asm-x86/processor.h | 1 | ||||
-rw-r--r-- | xen/include/asm-x86/smp.h | 2 | ||||
-rw-r--r-- | xen/include/xen/smp.h | 2 |
11 files changed, 104 insertions, 44 deletions
diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c index 1241e50921..4b49e17f37 100644 --- a/xen/arch/x86/cpu/amd.c +++ b/xen/arch/x86/cpu/amd.c @@ -193,23 +193,30 @@ static void __init init_amd(struct cpuinfo_x86 *c) } display_cacheinfo(c); - detect_ht(c); - -#ifdef CONFIG_X86_HT - /* AMD dual core looks like HT but isn't really. Hide it from the - scheduler. This works around problems with the domain scheduler. - Also probably gives slightly better scheduling and disables - SMT nice which is harmful on dual core. - TBD tune the domain scheduler for dual core. */ - 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; } + +#ifdef CONFIG_X86_HT + /* + * On a AMD dual core setup the lower bits of the APIC id + * distingush the cores. Assumes number of cores is a power + * of two. + */ + if (c->x86_num_cores > 1) { + int cpu = smp_processor_id(); + unsigned bits = 0; + while ((1 << bits) < c->x86_num_cores) + bits++; + cpu_core_id[cpu] = phys_proc_id[cpu] & ((1<<bits)-1); + phys_proc_id[cpu] >>= bits; + printk(KERN_INFO "CPU %d(%d) -> Core %d\n", + cpu, c->x86_num_cores, cpu_core_id[cpu]); + } +#endif } static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size) diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c index fcb5c16ecb..49661af7d8 100644 --- a/xen/arch/x86/cpu/common.c +++ b/xen/arch/x86/cpu/common.c @@ -186,7 +186,7 @@ static inline int flag_is_changeable_p(unsigned long flag) /* Probe for the CPUID instruction */ -int __init have_cpuid_p(void) +static int __init have_cpuid_p(void) { return flag_is_changeable_p(X86_EFLAGS_ID); } @@ -194,7 +194,7 @@ int __init have_cpuid_p(void) /* Do minimum CPU detection early. Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment. The others are not touched to avoid unwanted side effects. */ -void __init early_cpu_detect(void) +static void __init early_cpu_detect(void) { struct cpuinfo_x86 *c = &boot_cpu_data; @@ -228,6 +228,10 @@ void __init early_cpu_detect(void) } early_intel_workaround(c); + +#ifdef CONFIG_X86_HT + phys_proc_id[smp_processor_id()] = (cpuid_ebx(1) >> 24) & 0xff; +#endif } void __init generic_identify(struct cpuinfo_x86 * c) @@ -416,25 +420,15 @@ void __init identify_cpu(struct cpuinfo_x86 *c) mcheck_init(c); #endif } -/* - * Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c - */ - -void __init dodgy_tsc(void) -{ - if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) || - ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC )) - cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data); -} #ifdef CONFIG_X86_HT 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)) + if (!cpu_has(c, X86_FEATURE_HT) || cpu_has(c, X86_FEATURE_CMP_LEGACY)) return; cpuid(1, &eax, &ebx, &ecx, &edx); @@ -443,7 +437,6 @@ void __init detect_ht(struct cpuinfo_x86 *c) 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) { @@ -452,21 +445,34 @@ void __init detect_ht(struct cpuinfo_x86 *c) 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 @@ -511,7 +517,6 @@ extern int amd_init_cpu(void); extern int centaur_init_cpu(void); extern int transmeta_init_cpu(void); extern int rise_init_cpu(void); -void early_cpu_detect(void); void __init early_cpu_init(void) { diff --git a/xen/arch/x86/cpu/cpu.h b/xen/arch/x86/cpu/cpu.h index 9df38d993c..5a1d4f163e 100644 --- a/xen/arch/x86/cpu/cpu.h +++ b/xen/arch/x86/cpu/cpu.h @@ -25,7 +25,6 @@ extern int get_model_name(struct cpuinfo_x86 *c); extern void display_cacheinfo(struct cpuinfo_x86 *c); extern void generic_identify(struct cpuinfo_x86 * c); -extern int have_cpuid_p(void); extern void early_intel_workaround(struct cpuinfo_x86 *c); diff --git a/xen/arch/x86/cpu/intel.c b/xen/arch/x86/cpu/intel.c index 861723719b..ef713eb95e 100644 --- a/xen/arch/x86/cpu/intel.c +++ b/xen/arch/x86/cpu/intel.c @@ -74,6 +74,27 @@ static void __init Intel_errata_workarounds(struct cpuinfo_x86 *c) } +/* + * 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; @@ -136,6 +157,8 @@ static void __init init_intel(struct cpuinfo_x86 *c) if ( p ) strcpy(c->x86_model_id, p); + c->x86_num_cores = num_cpu_cores(c); + detect_ht(c); /* Work around errata */ diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c index e8979417ec..2a269f11b6 100644 --- a/xen/arch/x86/dom0_ops.c +++ b/xen/arch/x86/dom0_ops.c @@ -179,8 +179,8 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op) { dom0_physinfo_t *pi = &op->u.physinfo; - pi->ht_per_core = ht_per_core; - pi->cores = num_online_cpus() / ht_per_core; + pi->ht_per_core = smp_num_siblings; + pi->cores = boot_cpu_data.x86_num_cores; pi->total_pages = max_page; pi->free_pages = avail_domheap_pages(); pi->cpu_khz = cpu_khz; diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 0903967796..b0ebecfcee 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -66,7 +66,6 @@ boolean_param("noapic", skip_ioapic_setup); int early_boot = 1; -int ht_per_core = 1; cpumask_t cpu_present_map; /* Limits of Xen heap, used to initialise the allocator. */ diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index 80fe8122a4..c9e1ac9151 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -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; @@ -923,6 +925,8 @@ 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; +EXPORT_SYMBOL(cpu_core_map); static void __init smp_boot_cpus(unsigned int max_cpus) { @@ -947,6 +951,9 @@ static void __init smp_boot_cpus(unsigned int max_cpus) 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! @@ -959,6 +966,8 @@ static void __init smp_boot_cpus(unsigned int max_cpus) printk(KERN_NOTICE "Local APIC not detected." " Using dummy APIC emulation.\n"); map_cpu_to_logical_apicid(); + cpu_set(0, cpu_sibling_map[0]); + cpu_set(0, cpu_core_map[0]); return; } @@ -1079,10 +1088,13 @@ static void __init smp_boot_cpus(unsigned int max_cpus) * 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)) @@ -1092,7 +1104,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) 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]); } @@ -1102,8 +1114,22 @@ static void __init smp_boot_cpus(unsigned int max_cpus) cpu_set(cpu, cpu_sibling_map[cpu]); } - if (siblings != smp_num_siblings) + if (siblings != smp_num_siblings) { printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", 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]; + } } if (nmi_watchdog == NMI_LOCAL_APIC) diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index 216af3854a..8b3dd1edbc 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -184,8 +184,8 @@ long do_dom0_op(dom0_op_t *u_dom0_op) * domains will all share the second HT of each CPU. Since dom0 is on * CPU 0, we favour high numbered CPUs in the event of a tie. */ - pro = ht_per_core - 1; - for ( i = pro; i < num_online_cpus(); i += ht_per_core ) + pro = smp_num_siblings - 1; + for ( i = pro; i < num_online_cpus(); i += smp_num_siblings ) if ( cnt[i] <= cnt[pro] ) pro = i; diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index bec90dbab0..82b8cbce62 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -181,6 +181,7 @@ extern struct cpuinfo_x86 cpu_data[]; #endif extern int phys_proc_id[NR_CPUS]; +extern int cpu_core_id[NR_CPUS]; extern void identify_cpu(struct cpuinfo_x86 *); extern void print_cpu_info(struct cpuinfo_x86 *); diff --git a/xen/include/asm-x86/smp.h b/xen/include/asm-x86/smp.h index c70f4d90fc..552b699bc4 100644 --- a/xen/include/asm-x86/smp.h +++ b/xen/include/asm-x86/smp.h @@ -8,6 +8,7 @@ #include <xen/config.h> #include <xen/kernel.h> #include <xen/cpumask.h> +#include <asm/current.h> #endif #ifdef CONFIG_X86_LOCAL_APIC @@ -34,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_invalidate_rcv(void); /* Process an NMI */ diff --git a/xen/include/xen/smp.h b/xen/include/xen/smp.h index 2004211589..57f7580ade 100644 --- a/xen/include/xen/smp.h +++ b/xen/include/xen/smp.h @@ -58,8 +58,6 @@ static inline int on_each_cpu(void (*func) (void *info), void *info, return ret; } -extern int ht_per_core; - extern volatile unsigned long smp_msg_data; extern volatile int smp_src_cpu; extern volatile int smp_msg_id; |