Print this page
*** NO COMMENTS ***

@@ -158,11 +158,12 @@
         "aes",
         "pclmulqdq",
         "xsave",
         "avx",
         "vmx",
-        "svm"
+        "svm",
+        "topoext"
 };
 
 boolean_t
 is_x86_feature(void *featureset, uint_t feature)
 {

@@ -267,11 +268,11 @@
  * cpuid we cache in the cpuid_info data structure; the
  * remaining elements are accessible via the cpuid instruction.
  */
 
 #define NMAX_CPI_STD    6               /* eax = 0 .. 5 */
-#define NMAX_CPI_EXTD   0x1c            /* eax = 0x80000000 .. 0x8000001b */
+#define NMAX_CPI_EXTD   0x1f            /* eax = 0x80000000 .. 0x8000001e */
 
 /*
  * Some terminology needs to be explained:
  *  - Socket: Something that can be plugged into a motherboard.
  *  - Package: Same as socket

@@ -281,10 +282,12 @@
  *    "subprocessor" embedded in a package. These subprocessors (nodes)
  *    are fully-functional processors themselves with cores, caches,
  *    memory controllers, PCI configuration spaces. They are connected
  *    inside the package with Hypertransport links. On single-node
  *    processors, processor node is equivalent to chip/socket/package.
+ *  - Compute Unit: Some AMD processors pair cores in "compute units" that
+ *    share the FPU and the L1I and L2 caches.
  */
 
 struct cpuid_info {
         uint_t cpi_pass;                /* last pass completed */
         /*

@@ -341,10 +344,12 @@
         struct mwait_info cpi_mwait;    /* fn 5: monitor/mwait info */
         uint32_t cpi_apicid;
         uint_t cpi_procnodeid;          /* AMD: nodeID on HT, Intel: chipid */
         uint_t cpi_procnodes_per_pkg;   /* AMD: # of nodes in the package */
                                         /* Intel: 1 */
+        uint_t cpi_compunitid;          /* AMD: compute unit ID, Intel: coreid */
+        uint_t cpi_cores_per_compunit;  /* AMD: # of cores in the compute unit */
 
         struct xsave_info cpi_xsave;    /* fn D: xsave/xrestor info */
 };
 
 

@@ -725,19 +730,21 @@
                  */
                 cpi->cpi_coreid = cpi->cpi_chipid;
                 cpi->cpi_pkgcoreid = 0;
         }
         cpi->cpi_procnodeid = cpi->cpi_chipid;
+        cpi->cpi_compunitid = cpi->cpi_coreid;
 }
 
 static void
 cpuid_amd_getids(cpu_t *cpu)
 {
         int i, first_half, coreidsz;
         uint32_t nb_caps_reg;
         uint_t node2_1;
         struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
+        struct cpuid_regs *cp;
 
         /*
          * AMD CMP chips currently have a single thread per core.
          *
          * Since no two cpus share a core we must assign a distinct coreid

@@ -751,13 +758,19 @@
          * All processors in the system have the same number of enabled
          * cores. Cores within a processor are always numbered sequentially
          * from 0 regardless of how many or which are disabled, and there
          * is no way for operating system to discover the real core id when some
          * are disabled.
+         *
+         * In family 0x15, the cores come in pairs called compute units. They
+         * share L1I and L2 caches and the FPU. Enumeration of this features is
+         * simplified by the new topology extensions CPUID leaf, indicated by the
+         * X86 feature X86FSET_TOPOEXT.
          */
 
         cpi->cpi_coreid = cpu->cpu_id;
+        cpi->cpi_compunitid = cpu->cpu_id;
 
         if (cpi->cpi_xmaxeax >= 0x80000008) {
 
                 coreidsz = BITX((cpi)->cpi_extd[8].cp_ecx, 15, 12);
 

@@ -782,12 +795,22 @@
 
         cpi->cpi_clogid = cpi->cpi_pkgcoreid =
             cpi->cpi_apicid & ((1<<coreidsz) - 1);
         cpi->cpi_ncpu_per_chip = cpi->cpi_ncore_per_chip;
 
-        /* Get nodeID */
-        if (cpi->cpi_family == 0xf) {
+        /* Get node ID, compute unit ID */
+        if (is_x86_feature(x86_featureset, X86FSET_TOPOEXT) &&
+            cpi->cpi_xmaxeax >= 0x8000001e) {
+                cp = &cpi->cpi_extd[0x1e];
+                cp->cp_eax = 0x8000001e;
+                (void) __cpuid_insn(cp);
+
+                cpi->cpi_procnodes_per_pkg = BITX(cp->cp_ecx, 10, 8) + 1;
+                cpi->cpi_procnodeid = BITX(cp->cp_ecx, 7, 0);
+                cpi->cpi_cores_per_compunit = BITX(cp->cp_ebx, 15, 8) + 1;
+                cpi->cpi_compunitid = BITX(cp->cp_ebx, 7, 0);
+        } else if (cpi->cpi_family == 0xf || cpi->cpi_family >= 0x11) {
                 cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7;
                 cpi->cpi_chipid = cpi->cpi_procnodeid;
         } else if (cpi->cpi_family == 0x10) {
                 /*
                  * See if we are a multi-node processor.

@@ -835,13 +858,10 @@
                                             first_half;
 
                                 cpi->cpi_chipid = cpi->cpi_procnodeid >> 1;
                         }
                 }
-        } else if (cpi->cpi_family >= 0x11) {
-                cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7;
-                cpi->cpi_chipid = cpi->cpi_procnodeid;
         } else {
                 cpi->cpi_procnodeid = 0;
                 cpi->cpi_chipid = cpi->cpi_procnodeid;
         }
 }

@@ -1435,10 +1455,14 @@
                         }
 
                         if (cp->cp_ecx & CPUID_AMD_ECX_SVM) {
                                 add_x86_feature(featureset, X86FSET_SVM);
                         }
+
+                        if (cp->cp_ecx & CPUID_AMD_ECX_TOPOEXT) {
+                                add_x86_feature(featureset, X86FSET_TOPOEXT);
+                        }
                         break;
                 default:
                         break;
                 }
 

@@ -1543,10 +1567,11 @@
                 remove_x86_feature(featureset, X86FSET_HTT);
         }
 
         cpi->cpi_apicid = CPI_APIC_ID(cpi);
         cpi->cpi_procnodes_per_pkg = 1;
+        cpi->cpi_cores_per_compunit = 1;
         if (is_x86_feature(featureset, X86FSET_HTT) == B_FALSE &&
             is_x86_feature(featureset, X86FSET_CMP) == B_FALSE) {
                 /*
                  * Single-core single-threaded processors.
                  */

@@ -1569,10 +1594,11 @@
                          * assumed to have single cores.
                          */
                         cpi->cpi_coreid = cpi->cpi_chipid;
                         cpi->cpi_pkgcoreid = 0;
                         cpi->cpi_procnodeid = cpi->cpi_chipid;
+                        cpi->cpi_compunitid = cpi->cpi_chipid;
                 }
         }
 
         /*
          * Synthesize chip "revision" and socket type

@@ -2998,10 +3024,24 @@
 {
         ASSERT(cpuid_checkpass(cpu, 1));
         return (cpu->cpu_m.mcpu_cpi->cpi_procnodes_per_pkg);
 }
 
+uint_t
+cpuid_get_compunitid(cpu_t *cpu)
+{
+        ASSERT(cpuid_checkpass(cpu, 1));
+        return (cpu->cpu_m.mcpu_cpi->cpi_compunitid);
+}
+
+uint_t
+cpuid_get_cores_per_compunit(cpu_t *cpu)
+{
+        ASSERT(cpuid_checkpass(cpu, 1));
+        return (cpu->cpu_m.mcpu_cpi->cpi_cores_per_compunit);
+}
+
 /*ARGSUSED*/
 int
 cpuid_have_cr8access(cpu_t *cpu)
 {
 #if defined(__amd64)