x86[_64]: Add CPU topology detection for Intel processors

This commit is contained in:
Pawel Dziepak 2013-10-02 01:19:17 +02:00
parent 4110b730db
commit 8ec897323e
2 changed files with 207 additions and 0 deletions

View File

@ -31,6 +31,15 @@ namespace BKernel {
using BKernel::Thread;
typedef enum cpu_topology_level {
CPU_TOPOLOGY_SMT,
CPU_TOPOLOGY_CORE,
CPU_TOPOLOGY_PACKAGE,
//
CPU_TOPOLOGY_LEVELS
} cpu_topology_level;
/* CPU local data structure */
typedef struct cpu_ent {
@ -56,6 +65,9 @@ typedef struct cpu_ent {
bool invoke_scheduler_if_idle;
bool disabled;
// CPU topology information
int topology_id[CPU_TOPOLOGY_LEVELS];
// arch-specific stuff
arch_cpu_info arch;
} cpu_ent __attribute__((aligned(64)));

View File

@ -34,6 +34,7 @@
#define DUMP_FEATURE_STRING 1
#define DUMP_CPU_TOPOLOGY 1
/* cpu vendor info */
@ -122,6 +123,37 @@ x86_optimized_functions gOptimizedFunctions = {
&memset_generic_end
};
/* CPU topology information */
static uint32 (*getCPUTopologyID)(int currentCPU) = NULL;
static uint32 sHierarchyMask[CPU_TOPOLOGY_LEVELS];
static uint32 sHierarchyShift[CPU_TOPOLOGY_LEVELS];
// http://graphics.stanford.edu/~seander/bithacks.html
static inline uint32
nextPowerOf2(uint32 v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
// http://graphics.stanford.edu/~seander/bithacks.html
static inline uint32
countSetBits(uint32 v)
{
v = v - ((v >> 1) & 0x55555555);
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
}
static status_t
acpi_shutdown(bool rebootSystem)
@ -506,6 +538,167 @@ dump_feature_string(int currentCPU, cpu_ent* cpu)
#endif // DUMP_FEATURE_STRING
static uint32
getIntelCPUInitialx2APICID(int currentCPU)
{
(void)currentCPU;
cpuid_info cpuid;
get_current_cpuid(&cpuid, 11, 0);
return cpuid.regs.edx;
}
static inline status_t
detectIntelCPUTopologyx2APIC(int maxBasicLeaf)
{
if (maxBasicLeaf < 11)
return B_UNSUPPORTED;
const int kLevelCount = CPU_TOPOLOGY_LEVELS;
uint8 hierarchyLevels[kLevelCount];
int currentLevel = 0;
int levelType;
int levelsSet = 0;
do {
cpuid_info cpuid;
get_current_cpuid(&cpuid, 11, currentLevel);
if (currentLevel == 0 && cpuid.regs.ebx == 0)
return B_UNSUPPORTED;
levelType = (cpuid.regs.ecx >> 8) & 0xff;
switch (levelType) {
case 1: // SMT
hierarchyLevels[CPU_TOPOLOGY_SMT] = cpuid.regs.eax & 0x1f;
levelsSet |= 1;
break;
case 2: // core
hierarchyLevels[CPU_TOPOLOGY_CORE] = cpuid.regs.eax & 0x1f;
levelsSet |= 2;
break;
}
currentLevel++;
} while(levelType != 0 && levelsSet != 3);
getCPUTopologyID = getIntelCPUInitialx2APICID;
for (int i = 0; i < kLevelCount; i++) {
uint32 mask = ~uint32(0);
if (i < kLevelCount - 1)
mask = (1 << hierarchyLevels[i]) - 1;
if (i > 0)
mask &= ~sHierarchyMask[i - 1];
sHierarchyMask[i] = mask;
sHierarchyShift[i] = i > 0 ? hierarchyLevels[i - 1] : 0;
}
return B_OK;
}
static uint32
getIntelCPULegacyInitialAPICID(int currentCPU)
{
(void)currentCPU;
cpuid_info cpuid;
get_current_cpuid(&cpuid, 1, 0);
return cpuid.regs.ebx >> 24;
}
static inline void
detectIntelCPUTopologyLegacy(int maxBasicLeaf)
{
getCPUTopologyID = getIntelCPULegacyInitialAPICID;
cpuid_info cpuid;
get_current_cpuid(&cpuid, 1, 0);
int maxLogicalID = nextPowerOf2((cpuid.regs.ebx >> 16) & 0xff);
int maxCoreID = 1;
if (maxBasicLeaf >= 4) {
get_current_cpuid(&cpuid, 4, 0);
maxCoreID = nextPowerOf2((cpuid.regs.eax >> 26) + 1);
}
ASSERT(maxLogicalID >= maxCoreID);
const int kMaxSMTID = maxLogicalID / maxCoreID;
sHierarchyMask[CPU_TOPOLOGY_SMT] = kMaxSMTID - 1;
sHierarchyShift[CPU_TOPOLOGY_SMT] = 0;
sHierarchyMask[CPU_TOPOLOGY_CORE] = (maxCoreID - 1) * kMaxSMTID;
sHierarchyShift[CPU_TOPOLOGY_CORE]
= countSetBits(sHierarchyShift[CPU_TOPOLOGY_SMT]);
const uint32 kSinglePackageMask = sHierarchyMask[CPU_TOPOLOGY_SMT]
| sHierarchyMask[CPU_TOPOLOGY_CORE];
sHierarchyMask[CPU_TOPOLOGY_PACKAGE] = ~kSinglePackageMask;
sHierarchyShift[CPU_TOPOLOGY_PACKAGE] = countSetBits(kSinglePackageMask);
}
static uint32
getSimpleCPUTopologyID(int currentCPU)
{
return currentCPU;
}
static inline int
getTopologyLevelID(uint32 id, cpu_topology_level level)
{
ASSERT(level < CPU_TOPOLOGY_LEVELS);
return (id & sHierarchyMask[level]) >> sHierarchyShift[level];
}
static void
detectCPUTopology(int currentCPU, cpu_ent* cpu, int maxBasicLeaf)
{
if (currentCPU == 0) {
if (x86_check_feature(IA32_FEATURE_HTT, FEATURE_COMMON)) {
if (cpu->arch.vendor == VENDOR_INTEL) {
status_t result = detectIntelCPUTopologyx2APIC(maxBasicLeaf);
if (result != B_OK)
detectIntelCPUTopologyLegacy(maxBasicLeaf);
return;
}
}
dprintf("No CPU topology information available.\n");
getCPUTopologyID = getSimpleCPUTopologyID;
memset(sHierarchyMask, 0, sizeof(sHierarchyMask));
sHierarchyMask[CPU_TOPOLOGY_PACKAGE] = ~uint32(0);
memset(sHierarchyShift, 0, sizeof(sHierarchyShift));
}
ASSERT(getCPUTopologyID != NULL);
int topologyID = getCPUTopologyID(currentCPU);
cpu->topology_id[CPU_TOPOLOGY_SMT]
= getTopologyLevelID(topologyID, CPU_TOPOLOGY_SMT);
cpu->topology_id[CPU_TOPOLOGY_CORE]
= getTopologyLevelID(topologyID, CPU_TOPOLOGY_CORE);
cpu->topology_id[CPU_TOPOLOGY_PACKAGE]
= getTopologyLevelID(topologyID, CPU_TOPOLOGY_PACKAGE);
#if DUMP_CPU_TOPOLOGY
dprintf("CPU %d: apic id %d, package %d, core %d, smt %d\n", currentCPU,
topologyID, cpu->topology_id[CPU_TOPOLOGY_PACKAGE],
cpu->topology_id[CPU_TOPOLOGY_CORE],
cpu->topology_id[CPU_TOPOLOGY_SMT]);
#endif
}
static void
detect_cpu(int currentCPU)
{
@ -621,6 +814,8 @@ detect_cpu(int currentCPU)
cpu->arch.feature[FEATURE_6_ECX] = cpuid.regs.ecx;
}
detectCPUTopology(currentCPU, cpu, maxBasicLeaf);
#if DUMP_FEATURE_STRING
dump_feature_string(currentCPU, cpu);
#endif