+#include <i386/pmCPU.h>
+#include <i386/bit_routines.h>
+
+#define DIVISOR_GUARD(denom) \
+ if ((denom) == 0) { \
+ kprintf("%s: %d Zero divisor: " #denom, \
+ __FILE__, __LINE__); \
+ }
+
+static void debug_topology_print(void);
+
+boolean_t topo_dbg = FALSE;
+
+x86_pkg_t *x86_pkgs = NULL;
+uint32_t num_Lx_caches[MAX_CACHE_DEPTH] = { 0 };
+
+static x86_pkg_t *free_pkgs = NULL;
+static x86_die_t *free_dies = NULL;
+static x86_core_t *free_cores = NULL;
+static uint32_t num_dies = 0;
+
+static x86_cpu_cache_t *x86_caches = NULL;
+static uint32_t num_caches = 0;
+
+static boolean_t topoParmsInited = FALSE;
+x86_topology_parameters_t topoParms;
+
+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)
+{
+ i386_cpu_info_t *cpuinfo;
+
+ cpuinfo = cpuid_info();
+ return(cpuinfo->thread_count > cpuinfo->core_count);
+}
+
+static x86_cpu_cache_t *
+x86_cache_alloc(void)
+{
+ x86_cpu_cache_t *cache;
+ int i;
+
+ if (x86_caches == NULL) {
+ cache = kalloc(sizeof(x86_cpu_cache_t) + (MAX_CPUS * sizeof(x86_lcpu_t *)));
+ if (cache == NULL)
+ return(NULL);
+ } else {
+ cache = x86_caches;
+ x86_caches = cache->next;
+ cache->next = NULL;
+ }
+
+ bzero(cache, sizeof(x86_cpu_cache_t));
+ cache->next = NULL;
+ cache->maxcpus = MAX_CPUS;
+ for (i = 0; i < cache->maxcpus; i += 1) {
+ cache->cpus[i] = NULL;
+ }
+
+ num_caches += 1;
+
+ return(cache);
+}
+
+static void
+x86_LLC_info(void)
+{
+ int cache_level = 0;
+ uint32_t nCPUsSharing = 1;
+ i386_cpu_info_t *cpuinfo;
+ struct cpu_cache *cachep;
+ int i;
+
+ cpuinfo = cpuid_info();
+
+ for (i = 0, cachep = &cpu_caches[0]; i < LCACHE_MAX; i++, cachep++) {
+
+ 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 (cachep->level > cache_level) {
+ cache_level = cachep->level;
+
+ /*
+ * Save the number of CPUs sharing this cache.
+ */
+ nCPUsSharing = cpuinfo->cache_sharing[i];
+ }
+ }
+
+ /*
+ * Make the level of the LLC be 0 based.
+ */
+ topoParms.LLCDepth = cache_level - 1;
+
+ /*
+ * nCPUsSharing represents the *maximum* number of cores or
+ * logical CPUs sharing the cache.
+ */
+ topoParms.maxSharingLLC = nCPUsSharing;
+
+ topoParms.nCoresSharingLLC = nCPUsSharing / (cpuinfo->thread_count /
+ cpuinfo->core_count);
+ topoParms.nLCPUsSharingLLC = nCPUsSharing;
+
+ /*
+ * nCPUsSharing may not be the number of *active* cores or
+ * threads that are sharing the cache.
+ */
+ if (nCPUsSharing > cpuinfo->core_count)
+ topoParms.nCoresSharingLLC = cpuinfo->core_count;
+ if (nCPUsSharing > cpuinfo->thread_count)
+ topoParms.nLCPUsSharingLLC = cpuinfo->thread_count;
+}
+
+static void
+initTopoParms(void)
+{
+ 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.
+ */
+ x86_LLC_info();
+
+ /*
+ * 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.nLCoresPerDie = topoParms.nCoresSharingLLC;
+ topoParms.nPCoresPerDie = (topoParms.maxSharingLLC / topoParms.nPThreadsPerCore);
+
+ /*
+ * Compute the number of threads per die.
+ */
+ topoParms.nLThreadsPerDie = topoParms.nLThreadsPerCore * topoParms.nLCoresPerDie;
+ topoParms.nPThreadsPerDie = topoParms.nPThreadsPerCore * topoParms.nPCoresPerDie;
+
+ /*
+ * Compute the number of cores per package.
+ */
+ topoParms.nLCoresPerPackage = topoParms.nLCoresPerDie * topoParms.nLDiesPerPackage;
+ topoParms.nPCoresPerPackage = topoParms.nPCoresPerDie * topoParms.nPDiesPerPackage;
+
+ /*
+ * Compute the number of threads per package.
+ */
+ topoParms.nLThreadsPerPackage = topoParms.nLThreadsPerCore * topoParms.nLCoresPerPackage;
+ topoParms.nPThreadsPerPackage = topoParms.nPThreadsPerCore * topoParms.nPCoresPerPackage;
+
+ 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;
+}
+
+static void
+x86_cache_free(x86_cpu_cache_t *cache)
+{
+ num_caches -= 1;
+ if (cache->level > 0 && cache->level <= MAX_CACHE_DEPTH)
+ num_Lx_caches[cache->level - 1] -= 1;
+ cache->next = x86_caches;
+ x86_caches = cache;
+}