From 7ea07fd226314dc116e1089cb39196610300b406 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Wed, 17 Jun 2009 19:54:22 +0800 Subject: [PATCH] Correct the logical_cpus calculation in mptable_hyperthread_fixup() The original code extracts logical_cpus directly from the output of cpuid(eax=1), however, According to Intel's #253668, section 7.7 "(CPUID.1:EBX[23:16]) -- Indicates the maximum number of addressable ID for logical processors in a physical package." According to AMD's #25481 CPUID Fn0000_0001_EBX "LogicalProcessorCount is the number of threads per CPU core times the number of CPU cores per processor." So what we originally saved in logical_cpus is actually the upper limit of the logical CPUs per phyical CPU package. It may work correctly if there is only one logical CPU per physical CPU package detected in MP table. But if more than one logical CPUs per phyical CPU package are detected in the MP table, then the missing logical CPUs will not be detected later, since the code assumed that logical_cpus is the number of logical CPUs missed between two detected logical CPUs. We try to fix the problem by calculating the distances between two nearest APIC IDs. If all such distances for all detect logical CPUs are same, then the logical_cpus is set the calculated distance. The value extracted from cpuid(eax=1) just serves as the upper limit of the logical_cpus now. Reported-and-Tested-by: Robert Luciani --- sys/platform/pc32/i386/mp_machdep.c | 78 +++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/sys/platform/pc32/i386/mp_machdep.c b/sys/platform/pc32/i386/mp_machdep.c index f270c5de32..67963fb11d 100644 --- a/sys/platform/pc32/i386/mp_machdep.c +++ b/sys/platform/pc32/i386/mp_machdep.c @@ -1019,14 +1019,82 @@ mptable_pass2(struct mptable_pos *mpt) static void mptable_hyperthread_fixup(u_int id_mask) { - u_int i, id; + int i, id, lcpus_max; - /* Nothing to do if there is no HTT support. */ if ((cpu_feature & CPUID_HTT) == 0) return; - logical_cpus = (cpu_procinfo & CPUID_HTT_CORES) >> 16; - if (logical_cpus <= 1) + + lcpus_max = (cpu_procinfo & CPUID_HTT_CORES) >> 16; + if (lcpus_max <= 1) + return; + + if (strcmp(cpu_vendor, "GenuineIntel") == 0) { + /* + * INSTRUCTION SET REFERENCE, A-M (#253666) + * Page 3-181, Table 3-20 + * "The nearest power-of-2 integer that is not smaller + * than EBX[23:16] is the number of unique initial APIC + * IDs reserved for addressing different logical + * processors in a physical package." + */ + for (i = 0; ; ++i) { + if ((1 << i) >= lcpus_max) { + lcpus_max = 1 << i; + break; + } + } + } + + if (mp_naps == lcpus_max) { + /* We have nothing to fix */ return; + } else if (mp_naps == 1) { + /* XXX this may be incorrect */ + logical_cpus = lcpus_max; + } else { + int cur, prev, dist; + + /* + * Calculate the distances between two nearest + * APIC IDs. If all such distances are same, + * then it is the number of missing cpus that + * we are going to fill later. + */ + dist = cur = prev = -1; + for (id = 0; id < MAXCPU; ++id) { + if ((id_mask & 1 << id) == 0) + continue; + + cur = id; + if (prev >= 0) { + int new_dist = cur - prev; + + if (dist < 0) + dist = new_dist; + + /* + * Make sure that all distances + * between two nearest APIC IDs + * are same. + */ + if (dist != new_dist) + return; + } + prev = cur; + } + if (dist == 1) + return; + + /* Must be power of 2 */ + if (dist & (dist - 1)) + return; + + /* Can't exceed CPU package capacity */ + if (dist > lcpus_max) + logical_cpus = lcpus_max; + else + logical_cpus = dist; + } /* * For each APIC ID of a CPU that is set in the mask, @@ -1034,7 +1102,7 @@ mptable_hyperthread_fixup(u_int id_mask) * physical processor. If any of those ID's are * already in the table, then kill the fixup. */ - for (id = 0; id <= MAXCPU; id++) { + for (id = 0; id < MAXCPU; id++) { if ((id_mask & 1 << id) == 0) continue; /* First, make sure we are on a logical_cpus boundary. */ -- 2.41.0