- 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
This commit is contained in:
Jeff Roberson 2009-04-29 06:54:40 +00:00
parent 113dda8a7c
commit 82fcb0f192
8 changed files with 312 additions and 168 deletions

View File

@ -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. */

View File

@ -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++) {

View File

@ -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 */

View File

@ -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
*/

View File

@ -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);

View File

@ -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++) {

View File

@ -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 */

View File

@ -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
*/