/*
- * Copyright (c) 2003-2009 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2016 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
*/
#include <vm/vm_kern.h>
#include <kern/kalloc.h>
+#include <kern/timer_queue.h>
#include <mach/machine.h>
#include <i386/cpu_threads.h>
#include <i386/cpuid.h>
#include <i386/machine_cpu.h>
#include <i386/pmCPU.h>
-#include <i386/lock.h>
-
-//#define TOPO_DEBUG 1
-#if TOPO_DEBUG
-void debug_topology_print(void);
-#define DBG(x...) kprintf("DBG: " x)
-#else
-#define DBG(x...)
-#endif /* TOPO_DEBUG */
+#include <i386/bit_routines.h>
+#define DIVISOR_GUARD(denom) \
+ if ((denom) == 0) { \
+ kprintf("%s: %d Zero divisor: " #denom, \
+ __FILE__, __LINE__); \
+ }
-void validate_topology(void);
+static void debug_topology_print(void);
-/* Only for 32bit values */
-#define bit(n) (1U << (n))
-#define bitmask(h,l) ((bit(h)|(bit(h)-1)) & ~(bit(l)-1))
-#define bitfield(x,h,l) (((x) & bitmask(h,l)) >> l)
+boolean_t topo_dbg = FALSE;
x86_pkg_t *x86_pkgs = NULL;
uint32_t num_Lx_caches[MAX_CACHE_DEPTH] = { 0 };
decl_simple_lock_data(, x86_topo_lock);
+static struct cpu_cache {
+ int level; int type;
+} cpu_caches [LCACHE_MAX] = {
+ [L1D] = { 1, CPU_CACHE_TYPE_DATA },
+ [L1I] = { 1, CPU_CACHE_TYPE_INST },
+ [L2U] = { 2, CPU_CACHE_TYPE_UNIF },
+ [L3U] = { 3, CPU_CACHE_TYPE_UNIF },
+};
+
static boolean_t
cpu_is_hyperthreaded(void)
{
static void
x86_LLC_info(void)
{
- uint32_t index;
- uint32_t cache_info[4];
- uint32_t cache_level = 0;
+ int cache_level = 0;
uint32_t nCPUsSharing = 1;
i386_cpu_info_t *cpuinfo;
+ struct cpu_cache *cachep;
+ int i;
cpuinfo = cpuid_info();
- do_cpuid(0, cache_info);
-
- if (cache_info[eax] < 4) {
- /*
- * Processor does not support deterministic
- * cache information. Set LLC sharing to 1, since
- * we have no better information.
- */
- if (cpu_is_hyperthreaded()) {
- topoParms.nCoresSharingLLC = 1;
- topoParms.nLCPUsSharingLLC = 2;
- topoParms.maxSharingLLC = 2;
- } else {
- topoParms.nCoresSharingLLC = 1;
- topoParms.nLCPUsSharingLLC = 1;
- topoParms.maxSharingLLC = 1;
- }
- return;
- }
-
- for (index = 0; ; index += 1) {
- uint32_t this_level;
+ for (i = 0, cachep = &cpu_caches[0]; i < LCACHE_MAX; i++, cachep++) {
- cache_info[eax] = 4;
- cache_info[ecx] = index;
- cache_info[ebx] = 0;
- cache_info[edx] = 0;
-
- cpuid(cache_info);
-
- /*
- * See if all levels have been queried.
- */
- if (bitfield(cache_info[eax], 4, 0) == 0)
- break;
-
- /*
- * Get the current level.
- */
- this_level = bitfield(cache_info[eax], 7, 5);
+ if (cachep->type == 0 || cpuid_info()->cache_size[i] == 0)
+ continue;
/*
* Only worry about it if it's a deeper level than
* what we've seen before.
*/
- if (this_level > cache_level) {
- cache_level = this_level;
+ if (cachep->level > cache_level) {
+ cache_level = cachep->level;
/*
* Save the number of CPUs sharing this cache.
*/
- nCPUsSharing = bitfield(cache_info[eax], 25, 14) + 1;
+ nCPUsSharing = cpuinfo->cache_sharing[i];
}
}
*/
topoParms.maxSharingLLC = nCPUsSharing;
- topoParms.nCoresSharingLLC = nCPUsSharing;
+ topoParms.nCoresSharingLLC = nCPUsSharing / (cpuinfo->thread_count /
+ cpuinfo->core_count);
topoParms.nLCPUsSharingLLC = nCPUsSharing;
/*
{
i386_cpu_info_t *cpuinfo;
+ topoParms.stable = FALSE;
+
cpuinfo = cpuid_info();
+ PE_parse_boot_argn("-topo", &topo_dbg, sizeof(topo_dbg));
+
/*
* We need to start with getting the LLC information correct.
*/
/*
* Compute the number of threads (logical CPUs) per core.
*/
+ DIVISOR_GUARD(cpuinfo->core_count);
topoParms.nLThreadsPerCore = cpuinfo->thread_count / cpuinfo->core_count;
+ DIVISOR_GUARD(cpuinfo->cpuid_cores_per_package);
topoParms.nPThreadsPerCore = cpuinfo->cpuid_logical_per_package / cpuinfo->cpuid_cores_per_package;
/*
* Compute the number of dies per package.
*/
+ DIVISOR_GUARD(topoParms.nCoresSharingLLC);
topoParms.nLDiesPerPackage = cpuinfo->core_count / topoParms.nCoresSharingLLC;
+ DIVISOR_GUARD(topoParms.nPThreadsPerCore);
+ DIVISOR_GUARD(topoParms.maxSharingLLC / topoParms.nPThreadsPerCore);
topoParms.nPDiesPerPackage = cpuinfo->cpuid_cores_per_package / (topoParms.maxSharingLLC / topoParms.nPThreadsPerCore);
+
/*
* Compute the number of cores per die.
*/
topoParms.nLThreadsPerPackage = topoParms.nLThreadsPerCore * topoParms.nLCoresPerPackage;
topoParms.nPThreadsPerPackage = topoParms.nPThreadsPerCore * topoParms.nPCoresPerPackage;
- DBG("\nLogical Topology Parameters:\n");
- DBG("\tThreads per Core: %d\n", topoParms.nLThreadsPerCore);
- DBG("\tCores per Die: %d\n", topoParms.nLCoresPerDie);
- DBG("\tThreads per Die: %d\n", topoParms.nLThreadsPerDie);
- DBG("\tDies per Package: %d\n", topoParms.nLDiesPerPackage);
- DBG("\tCores per Package: %d\n", topoParms.nLCoresPerPackage);
- DBG("\tThreads per Package: %d\n", topoParms.nLThreadsPerPackage);
-
- DBG("\nPhysical Topology Parameters:\n");
- DBG("\tThreads per Core: %d\n", topoParms.nPThreadsPerCore);
- DBG("\tCores per Die: %d\n", topoParms.nPCoresPerDie);
- DBG("\tThreads per Die: %d\n", topoParms.nPThreadsPerDie);
- DBG("\tDies per Package: %d\n", topoParms.nPDiesPerPackage);
- DBG("\tCores per Package: %d\n", topoParms.nPCoresPerPackage);
- DBG("\tThreads per Package: %d\n", topoParms.nPThreadsPerPackage);
+ TOPO_DBG("\nCache Topology Parameters:\n");
+ TOPO_DBG("\tLLC Depth: %d\n", topoParms.LLCDepth);
+ TOPO_DBG("\tCores Sharing LLC: %d\n", topoParms.nCoresSharingLLC);
+ TOPO_DBG("\tThreads Sharing LLC: %d\n", topoParms.nLCPUsSharingLLC);
+ TOPO_DBG("\tmax Sharing of LLC: %d\n", topoParms.maxSharingLLC);
+
+ TOPO_DBG("\nLogical Topology Parameters:\n");
+ TOPO_DBG("\tThreads per Core: %d\n", topoParms.nLThreadsPerCore);
+ TOPO_DBG("\tCores per Die: %d\n", topoParms.nLCoresPerDie);
+ TOPO_DBG("\tThreads per Die: %d\n", topoParms.nLThreadsPerDie);
+ TOPO_DBG("\tDies per Package: %d\n", topoParms.nLDiesPerPackage);
+ TOPO_DBG("\tCores per Package: %d\n", topoParms.nLCoresPerPackage);
+ TOPO_DBG("\tThreads per Package: %d\n", topoParms.nLThreadsPerPackage);
+
+ TOPO_DBG("\nPhysical Topology Parameters:\n");
+ TOPO_DBG("\tThreads per Core: %d\n", topoParms.nPThreadsPerCore);
+ TOPO_DBG("\tCores per Die: %d\n", topoParms.nPCoresPerDie);
+ TOPO_DBG("\tThreads per Die: %d\n", topoParms.nPThreadsPerDie);
+ TOPO_DBG("\tDies per Package: %d\n", topoParms.nPDiesPerPackage);
+ TOPO_DBG("\tCores per Package: %d\n", topoParms.nPCoresPerPackage);
+ TOPO_DBG("\tThreads per Package: %d\n", topoParms.nPThreadsPerPackage);
topoParmsInited = TRUE;
}
x86_cpu_cache_t *root = NULL;
x86_cpu_cache_t *cur = NULL;
x86_cpu_cache_t *last = NULL;
- uint32_t index;
- uint32_t cache_info[4];
- uint32_t nsets;
-
- do_cpuid(0, cache_info);
-
- if (cache_info[eax] < 4) {
- /*
- * Processor does not support deterministic
- * cache information. Don't report anything
- */
- return NULL;
- }
-
- for (index = 0; ; index += 1) {
- cache_info[eax] = 4;
- cache_info[ecx] = index;
- cache_info[ebx] = 0;
- cache_info[edx] = 0;
-
- cpuid(cache_info);
+ struct cpu_cache *cachep;
+ int i;
- /*
- * See if all levels have been queried.
- */
- if (bitfield(cache_info[eax], 4, 0) == 0)
- break;
+ /*
+ * Cons up a list driven not by CPUID leaf 4 (deterministic cache params)
+ * but by the table above plus parameters already cracked from cpuid...
+ */
+ for (i = 0, cachep = &cpu_caches[0]; i < LCACHE_MAX; i++, cachep++) {
+ if (cachep->type == 0 || cpuid_info()->cache_size[i] == 0)
+ continue;
+
cur = x86_cache_alloc();
- if (cur == NULL) {
+ if (cur == NULL)
break;
- }
- cur->type = bitfield(cache_info[eax], 4, 0);
- cur->level = bitfield(cache_info[eax], 7, 5);
- cur->nlcpus = (bitfield(cache_info[eax], 25, 14) + 1);
- if (cpuid_info()->cpuid_model == 26)
- cur->nlcpus /= cpu_is_hyperthreaded() ? 1 : 2;
- cur->maxcpus = (bitfield(cache_info[eax], 25, 14) + 1);
- cur->line_size = bitfield(cache_info[ebx], 11, 0) + 1;
- cur->partitions = bitfield(cache_info[ebx], 21, 12) + 1;
- cur->ways = bitfield(cache_info[ebx], 31, 22) + 1;
- nsets = bitfield(cache_info[ecx], 31, 0) + 1;
- cur->cache_size = cur->line_size * cur->ways * cur->partitions * nsets;
+ cur->type = cachep->type;
+ cur->level = cachep->level;
+ cur->nlcpus = 0;
+ cur->maxcpus = cpuid_info()->cache_sharing[i];
+ cur->partitions = cpuid_info()->cache_partitions[i];
+ cur->cache_size = cpuid_info()->cache_size[i];
+ cur->line_size = cpuid_info()->cache_linesize;
if (last == NULL) {
root = cur;
last->next = cur;
last = cur;
}
-
- cur->nlcpus = 0;
num_Lx_caches[cur->level - 1] += 1;
}
-
- return(root);
+ return root;
}
+
static x86_cpu_cache_t *
x86_match_cache(x86_cpu_cache_t *list, x86_cpu_cache_t *matcher)
{
if (cur_cache->maxcpus == matcher->maxcpus
&& cur_cache->type == matcher->type
&& cur_cache->level == matcher->level
- && cur_cache->ways == matcher->ways
&& cur_cache->partitions == matcher->partitions
&& cur_cache->line_size == matcher->line_size
&& cur_cache->cache_size == matcher->cache_size)
lcpu->state = LCPU_OFF;
for (i = 0; i < MAX_CACHE_DEPTH; i += 1)
lcpu->caches[i] = NULL;
-
- lcpu->master = (lcpu->cpu_num == (unsigned int) master_cpu);
- lcpu->primary = (lcpu->pnum % topoParms.nPThreadsPerPackage) == 0;
}
static x86_core_t *
}
void
-x86_set_lcpu_numbers(x86_lcpu_t *lcpu)
+x86_set_logical_topology(x86_lcpu_t *lcpu, int pnum, int lnum)
{
- lcpu->lnum = lcpu->cpu_num % topoParms.nLThreadsPerCore;
-}
+ x86_core_t *core = lcpu->core;
+ x86_die_t *die = lcpu->die;
+ x86_pkg_t *pkg = lcpu->package;
+
+ assert(core != NULL);
+ assert(die != NULL);
+ assert(pkg != NULL);
-void
-x86_set_core_numbers(x86_core_t *core, x86_lcpu_t *lcpu)
-{
- core->pcore_num = lcpu->cpu_num / topoParms.nLThreadsPerCore;
+ lcpu->cpu_num = lnum;
+ lcpu->pnum = pnum;
+ lcpu->master = (lnum == master_cpu);
+ lcpu->primary = (lnum % topoParms.nLThreadsPerPackage) == 0;
+
+ lcpu->lnum = lnum % topoParms.nLThreadsPerCore;
+
+ core->pcore_num = lnum / topoParms.nLThreadsPerCore;
core->lcore_num = core->pcore_num % topoParms.nLCoresPerDie;
-}
-void
-x86_set_die_numbers(x86_die_t *die, x86_lcpu_t *lcpu)
-{
- die->pdie_num = lcpu->cpu_num / (topoParms.nLThreadsPerCore * topoParms.nLCoresPerDie);
+ die->pdie_num = lnum / (topoParms.nLThreadsPerCore*topoParms.nLCoresPerDie);
die->ldie_num = die->pdie_num % topoParms.nLDiesPerPackage;
-}
-void
-x86_set_pkg_numbers(x86_pkg_t *pkg, x86_lcpu_t *lcpu)
-{
- pkg->ppkg_num = lcpu->cpu_num / topoParms.nLThreadsPerPackage;
+ pkg->ppkg_num = lnum / topoParms.nLThreadsPerPackage;
pkg->lpkg_num = pkg->ppkg_num;
+
}
static x86_die_t *
simple_unlock(&x86_topo_lock);
pmCPUMarkRunning(cpup);
- etimer_resync_deadlines();
+ timer_resync_deadlines();
}
/*
* Called for a cpu to halt permanently
* (as opposed to halting and expecting an interrupt to awaken it).
*/
+__attribute__((noreturn))
void
cpu_thread_halt(void)
{
* after the complete topology is built and no other changes are being made.
*/
void
-validate_topology(void)
+x86_validate_topology(void)
{
x86_pkg_t *pkg;
x86_die_t *die;
uint32_t nCores;
uint32_t nCPUs;
+ if (topo_dbg)
+ debug_topology_print();
+
/*
* XXX
*
panic("Die %d points to package %d, should be %d",
die->pdie_num, die->package->lpkg_num, pkg->lpkg_num);
- DBG("Die(%d)->package %d\n",
+ TOPO_DBG("Die(%d)->package %d\n",
die->pdie_num, pkg->lpkg_num);
/*
* Make sure that the die has the correct number of cores.
*/
- DBG("Die(%d)->cores: ");
+ TOPO_DBG("Die(%d)->cores: ", die->pdie_num);
nCores = 0;
core = die->cores;
while (core != NULL) {
panic("Core %d points to die %d, should be %d",
core->pcore_num, core->die->pdie_num, die->pdie_num);
nCores += 1;
- DBG("%d ", core->pcore_num);
+ TOPO_DBG("%d ", core->pcore_num);
core = core->next_in_die;
}
- DBG("\n");
+ TOPO_DBG("\n");
if (nCores != topoParms.nLCoresPerDie)
panic("Should have %d Cores, but only found %d for Die %d",
/*
* Make sure that the die has the correct number of CPUs.
*/
- DBG("Die(%d)->lcpus: ", die->pdie_num);
+ TOPO_DBG("Die(%d)->lcpus: ", die->pdie_num);
nCPUs = 0;
lcpu = die->lcpus;
while (lcpu != NULL) {
panic("CPU %d points to die %d, should be %d",
lcpu->cpu_num, lcpu->die->pdie_num, die->pdie_num);
nCPUs += 1;
- DBG("%d ", lcpu->cpu_num);
+ TOPO_DBG("%d ", lcpu->cpu_num);
lcpu = lcpu->next_in_die;
}
- DBG("\n");
+ TOPO_DBG("\n");
if (nCPUs != topoParms.nLThreadsPerDie)
panic("Should have %d Threads, but only found %d for Die %d",
if (core->package != pkg)
panic("Core %d points to package %d, should be %d",
core->pcore_num, core->package->lpkg_num, pkg->lpkg_num);
- DBG("Core(%d)->package %d\n",
+ TOPO_DBG("Core(%d)->package %d\n",
core->pcore_num, pkg->lpkg_num);
/*
*/
nCPUs = 0;
lcpu = core->lcpus;
- DBG("Core(%d)->lcpus: ");
+ TOPO_DBG("Core(%d)->lcpus: ", core->pcore_num);
while (lcpu != NULL) {
if (lcpu->core == NULL)
panic("CPU(%d)->core is NULL",
if (lcpu->core != core)
panic("CPU %d points to core %d, should be %d",
lcpu->cpu_num, lcpu->core->pcore_num, core->pcore_num);
- DBG("%d ", lcpu->cpu_num);
+ TOPO_DBG("%d ", lcpu->cpu_num);
nCPUs += 1;
lcpu = lcpu->next_in_core;
}
- DBG("\n");
+ TOPO_DBG("\n");
if (nCPUs != topoParms.nLThreadsPerCore)
panic("Should have %d Threads, but only found %d for Core %d",
if (lcpu->package != pkg)
panic("CPU %d points to package %d, should be %d",
lcpu->cpu_num, lcpu->package->lpkg_num, pkg->lpkg_num);
- DBG("CPU(%d)->package %d\n",
+ TOPO_DBG("CPU(%d)->package %d\n",
lcpu->cpu_num, pkg->lpkg_num);
nCPUs += 1;
lcpu = lcpu->next_in_pkg;
}
}
-#if TOPO_DEBUG
/*
* Prints out the topology
*/
-void
+static void
debug_topology_print(void)
{
x86_pkg_t *pkg;
pkg = pkg->next;
}
}
-#endif /* TOPO_DEBUG */