x86: detect and initialize Intel CAT feature
authorChao Peng <chao.p.peng@linux.intel.com>
Tue, 7 Jul 2015 13:43:33 +0000 (15:43 +0200)
committerJan Beulich <jbeulich@suse.com>
Tue, 7 Jul 2015 13:43:33 +0000 (15:43 +0200)
Detect Intel Cache Allocation Technology(CAT) feature and store the
cpuid information for later use. Currently only L3 cache allocation is
supported. The L3 CAT features may vary among sockets so per-socket
feature information is stored. The initialization can happen either at
boot time or when CPU(s) is hot plugged after booting.

Signed-off-by: Chao Peng <chao.p.peng@linux.intel.com>
Use -1 as notifier priority. Fix typos.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
docs/misc/xen-command-line.markdown
xen/arch/x86/psr.c
xen/include/asm-x86/cpufeature.h
xen/include/asm-x86/psr.h

index aa684c0747527d92ad955e359377273f5ee6cc31..46620fb49a78df9be011507d382860742df59ff0 100644 (file)
@@ -1149,9 +1149,9 @@ This option can be specified more than once (up to 8 times at present).
 > `= <integer>`
 
 ### psr (Intel)
-> `= List of ( cmt:<boolean> | rmid_max:<integer> )`
+> `= List of ( cmt:<boolean> | rmid_max:<integer> | cat:<boolean> | cos_max:<integer> )`
 
-> Default: `psr=cmt:0,rmid_max:255`
+> Default: `psr=cmt:0,rmid_max:255,cat:0,cos_max:255`
 
 Platform Shared Resource(PSR) Services.  Intel Haswell and later server
 platforms offer information about the sharing of resources.
@@ -1161,6 +1161,12 @@ Monitoring ID(RMID) is used to bind the domain to corresponding shared
 resource.  RMID is a hardware-provided layer of abstraction between software
 and logical processors.
 
+To use the PSR cache allocation service for a certain domain, a capacity
+bitmasks(CBM) is used to bind the domain to corresponding shared resource.
+CBM represents cache capacity and indicates the degree of overlap and isolation
+between domains. In hypervisor a Class of Service(COS) ID is allocated for each
+unique CBM.
+
 The following resources are available:
 
 * Cache Monitoring Technology (Haswell and later).  Information regarding the
@@ -1171,6 +1177,11 @@ The following resources are available:
   total/local memory bandwidth. Follow the same options with Cache Monitoring
   Technology.
 
+* Cache Allocation Technology (Broadwell and later).  Information regarding
+  the cache allocation.
+  * `cat` instructs Xen to enable/disable Cache Allocation Technology.
+  * `cos_max` indicates the max value for COS ID.
+
 ### reboot
 > `= t[riple] | k[bd] | a[cpi] | p[ci] | P[ower] | e[fi] | n[o] [, [w]arm | [c]old]`
 
index 2490d22f382157577118015abc7e4bad1452b742..99a4bc32cb3f050bbd543cd3a78ea86928054a82 100644 (file)
 #include <asm/psr.h>
 
 #define PSR_CMT        (1<<0)
+#define PSR_CAT        (1<<1)
+
+struct psr_cat_socket_info {
+    unsigned int cbm_len;
+    unsigned int cos_max;
+};
 
 struct psr_assoc {
     uint64_t val;
 };
 
 struct psr_cmt *__read_mostly psr_cmt;
+
+static unsigned long *__read_mostly cat_socket_enable;
+static struct psr_cat_socket_info *__read_mostly cat_socket_info;
+
 static unsigned int __initdata opt_psr;
 static unsigned int __initdata opt_rmid_max = 255;
+static unsigned int __read_mostly opt_cos_max = 255;
 static uint64_t rmid_mask;
 static DEFINE_PER_CPU(struct psr_assoc, psr_assoc);
 
@@ -63,10 +74,14 @@ static void __init parse_psr_param(char *s)
             *val_str++ = '\0';
 
         parse_psr_bool(s, val_str, "cmt", PSR_CMT);
+        parse_psr_bool(s, val_str, "cat", PSR_CAT);
 
         if ( val_str && !strcmp(s, "rmid_max") )
             opt_rmid_max = simple_strtoul(val_str, NULL, 0);
 
+        if ( val_str && !strcmp(s, "cos_max") )
+            opt_cos_max = simple_strtoul(val_str, NULL, 0);
+
         s = ss + 1;
     } while ( ss );
 }
@@ -194,22 +209,103 @@ void psr_ctxt_switch_to(struct domain *d)
     }
 }
 
+static void cat_cpu_init(void)
+{
+    unsigned int eax, ebx, ecx, edx;
+    struct psr_cat_socket_info *info;
+    unsigned int socket;
+    unsigned int cpu = smp_processor_id();
+    const struct cpuinfo_x86 *c = cpu_data + cpu;
+
+    if ( !cpu_has(c, X86_FEATURE_CAT) || c->cpuid_level < PSR_CPUID_LEVEL_CAT )
+        return;
+
+    socket = cpu_to_socket(cpu);
+    if ( test_bit(socket, cat_socket_enable) )
+        return;
+
+    cpuid_count(PSR_CPUID_LEVEL_CAT, 0, &eax, &ebx, &ecx, &edx);
+    if ( ebx & PSR_RESOURCE_TYPE_L3 )
+    {
+        cpuid_count(PSR_CPUID_LEVEL_CAT, 1, &eax, &ebx, &ecx, &edx);
+        info = cat_socket_info + socket;
+        info->cbm_len = (eax & 0x1f) + 1;
+        info->cos_max = min(opt_cos_max, edx & 0xffff);
+
+        set_bit(socket, cat_socket_enable);
+        printk(XENLOG_INFO "CAT: enabled on socket %u, cos_max:%u, cbm_len:%u\n",
+               socket, info->cos_max, info->cbm_len);
+    }
+}
+
+static void cat_cpu_fini(unsigned int cpu)
+{
+    unsigned int socket = cpu_to_socket(cpu);
+
+    if ( !socket_cpumask[socket] || cpumask_empty(socket_cpumask[socket]) )
+        clear_bit(socket, cat_socket_enable);
+}
+
+static void __init init_psr_cat(void)
+{
+    if ( opt_cos_max < 1 )
+    {
+        printk(XENLOG_INFO "CAT: disabled, cos_max is too small\n");
+        return;
+    }
+
+    cat_socket_enable = xzalloc_array(unsigned long, BITS_TO_LONGS(nr_sockets));
+    cat_socket_info = xzalloc_array(struct psr_cat_socket_info, nr_sockets);
+
+    if ( !cat_socket_enable || !cat_socket_info )
+    {
+        xfree(cat_socket_enable);
+        cat_socket_enable = NULL;
+        xfree(cat_socket_info);
+        cat_socket_info = NULL;
+    }
+}
+
 static void psr_cpu_init(void)
 {
+    if ( cat_socket_info )
+        cat_cpu_init();
+
     psr_assoc_init();
 }
 
+static void psr_cpu_fini(unsigned int cpu)
+{
+    if ( cat_socket_info )
+        cat_cpu_fini(cpu);
+}
+
 static int cpu_callback(
     struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
-    if ( action == CPU_STARTING )
+    unsigned int cpu = (unsigned long)hcpu;
+
+    switch ( action )
+    {
+    case CPU_STARTING:
         psr_cpu_init();
+        break;
+    case CPU_DEAD:
+        psr_cpu_fini(cpu);
+        break;
+    }
 
     return NOTIFY_DONE;
 }
 
 static struct notifier_block cpu_nfb = {
-    .notifier_call = cpu_callback
+    .notifier_call = cpu_callback,
+    /*
+     * Ensure socket_cpumask is still valid in CPU_DEAD notification
+     * (E.g. our CPU_DEAD notification should be called ahead of
+     * cpu_smpboot_free).
+     */
+    .priority = -1
 };
 
 static int __init psr_presmp_init(void)
@@ -217,8 +313,11 @@ static int __init psr_presmp_init(void)
     if ( (opt_psr & PSR_CMT) && opt_rmid_max )
         init_psr_cmt(opt_rmid_max);
 
+    if ( opt_psr & PSR_CAT )
+        init_psr_cat();
+
     psr_cpu_init();
-    if ( psr_cmt_enabled() )
+    if ( psr_cmt_enabled() || cat_socket_info )
         register_cpu_notifier(&cpu_nfb);
 
     return 0;
index 63c1fe834cf50e965970d4001ccc45260bb3c03e..9a01563152c5e2a103ae1250babe62f55b13536e 100644 (file)
 #define X86_FEATURE_CMT        (7*32+12) /* Cache Monitoring Technology */
 #define X86_FEATURE_NO_FPU_SEL         (7*32+13) /* FPU CS/DS stored as zero */
 #define X86_FEATURE_MPX                (7*32+14) /* Memory Protection Extensions */
+#define X86_FEATURE_CAT        (7*32+15) /* Cache Allocation Technology */
 #define X86_FEATURE_RDSEED     (7*32+18) /* RDSEED instruction */
 #define X86_FEATURE_ADX                (7*32+19) /* ADCX, ADOX instructions */
 #define X86_FEATURE_SMAP       (7*32+20) /* Supervisor Mode Access Prevention */
index 12d593b6a562beb61eff2ad21cb555ffd6fcf41d..bdda1111dc03c97ee596996fc9741bd2cff6dbc8 100644 (file)
@@ -18,6 +18,9 @@
 
 #include <xen/types.h>
 
+/* CAT cpuid level */
+#define PSR_CPUID_LEVEL_CAT   0x10
+
 /* Resource Type Enumeration */
 #define PSR_RESOURCE_TYPE_L3            0x2