diff options
author | Jeff Roberson <jeff@FreeBSD.org> | 2009-04-29 06:54:40 +0000 |
---|---|---|
committer | Jeff Roberson <jeff@FreeBSD.org> | 2009-04-29 06:54:40 +0000 |
commit | 82fcb0f1927155bea9b2e90e86173cee61bc5b2c (patch) | |
tree | f7e33f7dc0c826db0e48cbe026fe789a938ff2b6 /sys/i386/i386/mp_machdep.c | |
parent | 113dda8a7c936995d64456bb2783bc56e0687281 (diff) | |
download | src-82fcb0f1927155bea9b2e90e86173cee61bc5b2c.tar.gz src-82fcb0f1927155bea9b2e90e86173cee61bc5b2c.zip |
- Add support for cpuid leaf 0xb. This allows us to determine the
topology of nehalem/corei7 based systems.
- Remove the cpu_cores/cpu_logical detection from identcpu.
- Describe the layout of the system in cpu_mp_announce().
Sponsored by: Nokia
Notes
Notes:
svn path=/head/; revision=191648
Diffstat (limited to 'sys/i386/i386/mp_machdep.c')
-rw-r--r-- | sys/i386/i386/mp_machdep.c | 201 |
1 files changed, 148 insertions, 53 deletions
diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c index e75df9d78544..ab15ffb3d614 100644 --- a/sys/i386/i386/mp_machdep.c +++ b/sys/i386/i386/mp_machdep.c @@ -213,6 +213,8 @@ int apic_cpuids[MAX_APIC_ID + 1]; static volatile u_int cpu_ipi_pending[MAXCPU]; static u_int boot_address; +static int cpu_logical; +static int cpu_cores; static void assign_cpu_ids(void); static void install_ap_tramp(void); @@ -234,13 +236,142 @@ mem_range_AP_init(void) mem_range_softc.mr_op->initAP(&mem_range_softc); } -struct cpu_group * -cpu_topo(void) +static void +topo_probe_0xb(void) +{ + int logical; + int p[4]; + int bits; + int type; + int cnt; + int i; + int x; + + /* We only support two levels for now. */ + for (i = 0; i < 3; i++) { + cpuid_count(0x0B, i, p); + bits = p[0] & 0x1f; + logical = p[1] &= 0xffff; + type = (p[2] >> 8) & 0xff; + if (type == 0 || logical == 0) + break; + for (cnt = 0, x = 0; x <= MAX_APIC_ID; x++) { + if (!cpu_info[x].cpu_present || + cpu_info[x].cpu_disabled) + continue; + if (x >> bits == boot_cpu_id >> bits) + cnt++; + } + if (type == CPUID_TYPE_SMT) + cpu_logical = cnt; + else if (type == CPUID_TYPE_CORE) + cpu_cores = cnt; + } + if (cpu_logical == 0) + cpu_logical = 1; + cpu_cores /= cpu_logical; +} + +static void +topo_probe_0x4(void) { + u_int threads_per_cache, p[4]; + u_int htt, cmp; + int i; + + htt = cmp = 1; + /* + * If this CPU supports HTT or CMP then mention the + * number of physical/logical cores it contains. + */ + if (cpu_feature & CPUID_HTT) + htt = (cpu_procinfo & CPUID_HTT_CORES) >> 16; + if (cpu_vendor_id == CPU_VENDOR_AMD && (amd_feature2 & AMDID2_CMP)) + cmp = (cpu_procinfo2 & AMDID_CMP_CORES) + 1; + else if (cpu_vendor_id == CPU_VENDOR_INTEL && (cpu_high >= 4)) { + cpuid_count(4, 0, p); + if ((p[0] & 0x1f) != 0) + cmp = ((p[0] >> 26) & 0x3f) + 1; + } + cpu_cores = cmp; + cpu_logical = htt / cmp; + + /* Setup the initial logical CPUs info. */ + if (cpu_feature & CPUID_HTT) + logical_cpus = (cpu_procinfo & CPUID_HTT_CORES) >> 16; + + /* + * Work out if hyperthreading is *really* enabled. This + * is made really ugly by the fact that processors lie: Dual + * core processors claim to be hyperthreaded even when they're + * not, presumably because they want to be treated the same + * way as HTT with respect to per-cpu software licensing. + * At the time of writing (May 12, 2005) the only hyperthreaded + * cpus are from Intel, and Intel's dual-core processors can be + * identified via the "deterministic cache parameters" cpuid + * calls. + */ + /* + * First determine if this is an Intel processor which claims + * to have hyperthreading support. + */ + if ((cpu_feature & CPUID_HTT) && cpu_vendor_id == CPU_VENDOR_INTEL) { + /* + * If the "deterministic cache parameters" cpuid calls + * are available, use them. + */ + if (cpu_high >= 4) { + /* Ask the processor about the L1 cache. */ + for (i = 0; i < 1; i++) { + cpuid_count(4, i, p); + threads_per_cache = ((p[0] & 0x3ffc000) >> 14) + 1; + if (hyperthreading_cpus < threads_per_cache) + hyperthreading_cpus = threads_per_cache; + if ((p[0] & 0x1f) == 0) + break; + } + } + + /* + * If the deterministic cache parameters are not + * available, or if no caches were reported to exist, + * just accept what the HTT flag indicated. + */ + if (hyperthreading_cpus == 0) + hyperthreading_cpus = logical_cpus; + } +} + +static void +topo_probe(void) +{ + + logical_cpus = logical_cpus_mask = 0; + if (cpu_high >= 0xb) + topo_probe_0xb(); + else if (cpu_high) + topo_probe_0x4(); if (cpu_cores == 0) - cpu_cores = 1; + cpu_cores = mp_ncpus; if (cpu_logical == 0) cpu_logical = 1; +} + +struct cpu_group * +cpu_topo(void) +{ + int cg_flags; + + /* + * Determine whether any threading flags are + * necessry. + */ + if (cpu_logical > 1 && hyperthreading_cpus) + cg_flags = CG_FLAG_HTT; + else if (cpu_logical > 1) + cg_flags = CG_FLAG_SMT; + else + cg_flags = 0; if (mp_ncpus % (cpu_cores * cpu_logical) != 0) { printf("WARNING: Non-uniform processors.\n"); printf("WARNING: Using suboptimal topology.\n"); @@ -255,17 +386,17 @@ cpu_topo(void) * Only HTT no multi-core. */ if (cpu_logical > 1 && cpu_cores == 1) - return (smp_topo_1level(CG_SHARE_L1, cpu_logical, CG_FLAG_HTT)); + return (smp_topo_1level(CG_SHARE_L1, cpu_logical, cg_flags)); /* * Only multi-core no HTT. */ if (cpu_cores > 1 && cpu_logical == 1) - return (smp_topo_1level(CG_SHARE_NONE, cpu_cores, 0)); + return (smp_topo_1level(CG_SHARE_L2, cpu_cores, cg_flags)); /* * Both HTT and multi-core. */ - return (smp_topo_2level(CG_SHARE_NONE, cpu_cores, - CG_SHARE_L1, cpu_logical, CG_FLAG_HTT)); + return (smp_topo_2level(CG_SHARE_L2, cpu_cores, + CG_SHARE_L1, cpu_logical, cg_flags)); } @@ -354,7 +485,6 @@ void cpu_mp_start(void) { int i; - u_int threads_per_cache, p[4]; /* Initialize the logical ID to APIC ID table. */ for (i = 0; i < MAXCPU; i++) { @@ -399,51 +529,8 @@ cpu_mp_start(void) KASSERT(boot_cpu_id == PCPU_GET(apic_id), ("BSP's APIC ID doesn't match boot_cpu_id")); - /* Setup the initial logical CPUs info. */ - logical_cpus = logical_cpus_mask = 0; - if (cpu_feature & CPUID_HTT) - logical_cpus = (cpu_procinfo & CPUID_HTT_CORES) >> 16; - - /* - * Work out if hyperthreading is *really* enabled. This - * is made really ugly by the fact that processors lie: Dual - * core processors claim to be hyperthreaded even when they're - * not, presumably because they want to be treated the same - * way as HTT with respect to per-cpu software licensing. - * At the time of writing (May 12, 2005) the only hyperthreaded - * cpus are from Intel, and Intel's dual-core processors can be - * identified via the "deterministic cache parameters" cpuid - * calls. - */ - /* - * First determine if this is an Intel processor which claims - * to have hyperthreading support. - */ - if ((cpu_feature & CPUID_HTT) && cpu_vendor_id == CPU_VENDOR_INTEL) { - /* - * If the "deterministic cache parameters" cpuid calls - * are available, use them. - */ - if (cpu_high >= 4) { - /* Ask the processor about the L1 cache. */ - for (i = 0; i < 1; i++) { - cpuid_count(4, i, p); - threads_per_cache = ((p[0] & 0x3ffc000) >> 14) + 1; - if (hyperthreading_cpus < threads_per_cache) - hyperthreading_cpus = threads_per_cache; - if ((p[0] & 0x1f) == 0) - break; - } - } - - /* - * If the deterministic cache parameters are not - * available, or if no caches were reported to exist, - * just accept what the HTT flag indicated. - */ - if (hyperthreading_cpus == 0) - hyperthreading_cpus = logical_cpus; - } + /* Probe logical/physical core configuration. */ + topo_probe(); assign_cpu_ids(); @@ -463,6 +550,14 @@ cpu_mp_announce(void) const char *hyperthread; int i; + printf("FreeBSD/SMP: %d package(s) x %d core(s)", + mp_ncpus / (cpu_cores * cpu_logical), cpu_cores); + if (hyperthreading_cpus > 1) + printf(" x %d HTT threads", cpu_logical); + else if (cpu_logical > 1) + printf(" x %d SMT threads", cpu_logical); + printf("\n"); + /* List active CPUs first. */ printf(" cpu0 (BSP): APIC ID: %2d\n", boot_cpu_id); for (i = 1; i < mp_ncpus; i++) { |