diff --git a/sys/amd64/amd64/identcpu.c b/sys/amd64/amd64/identcpu.c index a1112cc8d932..4ac0e5f34860 100644 --- a/sys/amd64/amd64/identcpu.c +++ b/sys/amd64/amd64/identcpu.c @@ -106,9 +106,6 @@ static struct { { CENTAUR_VENDOR_ID, CPU_VENDOR_CENTAUR }, /* CentaurHauls */ }; -int cpu_cores; -int cpu_logical; - extern int pq_l2size; extern int pq_l2nways; @@ -195,7 +192,6 @@ printcpuinfo(void) cpu_vendor_id == CPU_VENDOR_CENTAUR) { printf(" Stepping = %u", cpu_id & 0xf); if (cpu_high > 0) { - u_int cmp = 1, htt = 1; /* * Here we should probably set up flags indicating @@ -400,28 +396,6 @@ printcpuinfo(void) if (tsc_is_invariant) printf("\n TSC: P-state invariant"); - /* - * 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, regs); - if ((regs[0] & 0x1f) != 0) - cmp = ((regs[0] >> 26) & 0x3f) + 1; - } - cpu_cores = cmp; - cpu_logical = htt / cmp; - if (cmp > 1) - printf("\n Cores per package: %d", cmp); - if ((htt / cmp) > 1) - printf("\n Logical CPUs per core: %d", - cpu_logical); } } /* Avoid ugly blank lines: only print newline when we have to. */ diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c index a45b3987aa36..8bc47e58c685 100644 --- a/sys/amd64/amd64/mp_machdep.c +++ b/sys/amd64/amd64/mp_machdep.c @@ -160,6 +160,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 set_interrupt_apic_ids(void); @@ -181,13 +183,142 @@ mem_range_AP_init(void) mem_range_softc.mr_op->initAP(&mem_range_softc); } +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 = mp_ncpus; + if (cpu_logical == 0) + cpu_logical = 1; +} + struct cpu_group * cpu_topo(void) { - if (cpu_cores == 0) - cpu_cores = 1; - if (cpu_logical == 0) - cpu_logical = 1; + 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"); @@ -202,17 +333,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)); } /* @@ -318,7 +449,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++) { @@ -355,51 +485,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(); @@ -419,6 +506,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++) { diff --git a/sys/amd64/include/smp.h b/sys/amd64/include/smp.h index d2ff189f2f85..0a0e510a6a5d 100644 --- a/sys/amd64/include/smp.h +++ b/sys/amd64/include/smp.h @@ -36,10 +36,6 @@ extern int boot_cpu_id; extern struct pcb stoppcbs[]; extern int cpu_apic_ids[]; -/* global data in identcpu.c */ -extern int cpu_cores; -extern int cpu_logical; - /* IPI handlers */ inthand_t IDTVEC(invltlb), /* TLB shootdowns - global */ diff --git a/sys/amd64/include/specialreg.h b/sys/amd64/include/specialreg.h index eb2ff9b8f545..afc6580ea9ff 100644 --- a/sys/amd64/include/specialreg.h +++ b/sys/amd64/include/specialreg.h @@ -183,6 +183,13 @@ #define CPUID_HTT_CORES 0x00ff0000 #define CPUID_LOCAL_APIC_ID 0xff000000 +/* + * CPUID instruction 0xb ebx info. + */ +#define CPUID_TYPE_INVAL 0 +#define CPUID_TYPE_SMT 1 +#define CPUID_TYPE_CORE 2 + /* * AMD extended function 8000_0007h edx info */ diff --git a/sys/i386/i386/identcpu.c b/sys/i386/i386/identcpu.c index d2a02921f4a7..60907a530d36 100644 --- a/sys/i386/i386/identcpu.c +++ b/sys/i386/i386/identcpu.c @@ -159,9 +159,6 @@ static struct { #endif }; -int cpu_cores; -int cpu_logical; - #if defined(I586_CPU) && !defined(NO_F00F_HACK) int has_f00f_bug = 0; /* Initialized so that it can be patched. */ #endif @@ -690,7 +687,6 @@ printcpuinfo(void) if (cpu_vendor_id == CPU_VENDOR_CYRIX) printf(" DIR=0x%04x", cyrix_did); if (cpu_high > 0) { - u_int cmp = 1, htt = 1; /* * Here we should probably set up flags indicating @@ -895,28 +891,6 @@ printcpuinfo(void) if (tsc_is_invariant) printf("\n TSC: P-state invariant"); - /* - * 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, regs); - if ((regs[0] & 0x1f) != 0) - cmp = ((regs[0] >> 26) & 0x3f) + 1; - } - cpu_cores = cmp; - cpu_logical = htt / cmp; - if (cmp > 1) - printf("\n Cores per package: %d", cmp); - if ((htt / cmp) > 1) - printf("\n Logical CPUs per core: %d", - cpu_logical); } } else if (cpu_vendor_id == CPU_VENDOR_CYRIX) { printf(" DIR=0x%04x", cyrix_did); 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); } +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 = mp_ncpus; + if (cpu_logical == 0) + cpu_logical = 1; +} + struct cpu_group * cpu_topo(void) { - if (cpu_cores == 0) - cpu_cores = 1; - if (cpu_logical == 0) - cpu_logical = 1; + 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++) { diff --git a/sys/i386/include/smp.h b/sys/i386/include/smp.h index ef3cbbbe1dc9..33739ccf7c93 100644 --- a/sys/i386/include/smp.h +++ b/sys/i386/include/smp.h @@ -45,10 +45,6 @@ extern u_long *ipi_rendezvous_counts[MAXCPU]; extern u_long *ipi_lazypmap_counts[MAXCPU]; #endif -/* global data in identcpu.c */ -extern int cpu_cores; -extern int cpu_logical; - /* IPI handlers */ inthand_t IDTVEC(invltlb), /* TLB shootdowns - global */ diff --git a/sys/i386/include/specialreg.h b/sys/i386/include/specialreg.h index c3cbec72abd4..fa9cf8143bef 100644 --- a/sys/i386/include/specialreg.h +++ b/sys/i386/include/specialreg.h @@ -182,6 +182,13 @@ #define CPUID_HTT_CORES 0x00ff0000 #define CPUID_LOCAL_APIC_ID 0xff000000 +/* + * CPUID instruction 0xb ebx info. + */ +#define CPUID_TYPE_INVAL 0 +#define CPUID_TYPE_SMT 1 +#define CPUID_TYPE_CORE 2 + /* * AMD extended function 8000_0007h edx info */