Commit f0b13428 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'x86-cache-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86/cache updates from Thomas Gleixner:
 "A set of patches which add support for L2 cache partitioning to the
  Intel RDT facility"

* 'x86-cache-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/intel_rdt: Add command line parameter to control L2_CDP
  x86/intel_rdt: Enable L2 CDP in MSR IA32_L2_QOS_CFG
  x86/intel_rdt: Add two new resources for L2 Code and Data Prioritization (CDP)
  x86/intel_rdt: Enumerate L2 Code and Data Prioritization (CDP) feature
  x86/intel_rdt: Add L2CDP support in documentation
  x86/intel_rdt: Update documentation
parents a46d3f9b 31516de3
...@@ -3684,7 +3684,8 @@ ...@@ -3684,7 +3684,8 @@
rdt= [HW,X86,RDT] rdt= [HW,X86,RDT]
Turn on/off individual RDT features. List is: Turn on/off individual RDT features. List is:
cmt, mbmtotal, mbmlocal, l3cat, l3cdp, l2cat, mba. cmt, mbmtotal, mbmlocal, l3cat, l3cdp, l2cat, l2cdp,
mba.
E.g. to turn on cmt and turn off mba use: E.g. to turn on cmt and turn off mba use:
rdt=cmt,!mba rdt=cmt,!mba
......
...@@ -7,15 +7,24 @@ Tony Luck <tony.luck@intel.com> ...@@ -7,15 +7,24 @@ Tony Luck <tony.luck@intel.com>
Vikas Shivappa <vikas.shivappa@intel.com> Vikas Shivappa <vikas.shivappa@intel.com>
This feature is enabled by the CONFIG_INTEL_RDT Kconfig and the This feature is enabled by the CONFIG_INTEL_RDT Kconfig and the
X86 /proc/cpuinfo flag bits "rdt", "cqm", "cat_l3" and "cdp_l3". X86 /proc/cpuinfo flag bits:
RDT (Resource Director Technology) Allocation - "rdt_a"
CAT (Cache Allocation Technology) - "cat_l3", "cat_l2"
CDP (Code and Data Prioritization ) - "cdp_l3", "cdp_l2"
CQM (Cache QoS Monitoring) - "cqm_llc", "cqm_occup_llc"
MBM (Memory Bandwidth Monitoring) - "cqm_mbm_total", "cqm_mbm_local"
MBA (Memory Bandwidth Allocation) - "mba"
To use the feature mount the file system: To use the feature mount the file system:
# mount -t resctrl resctrl [-o cdp] /sys/fs/resctrl # mount -t resctrl resctrl [-o cdp[,cdpl2]] /sys/fs/resctrl
mount options are: mount options are:
"cdp": Enable code/data prioritization in L3 cache allocations. "cdp": Enable code/data prioritization in L3 cache allocations.
"cdpl2": Enable code/data prioritization in L2 cache allocations.
L2 and L3 CDP are controlled seperately.
RDT features are orthogonal. A particular system may support only RDT features are orthogonal. A particular system may support only
monitoring, only control, or both monitoring and control. monitoring, only control, or both monitoring and control.
......
...@@ -206,6 +206,7 @@ ...@@ -206,6 +206,7 @@
#define X86_FEATURE_RETPOLINE ( 7*32+12) /* Generic Retpoline mitigation for Spectre variant 2 */ #define X86_FEATURE_RETPOLINE ( 7*32+12) /* Generic Retpoline mitigation for Spectre variant 2 */
#define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* AMD Retpoline mitigation for Spectre variant 2 */ #define X86_FEATURE_RETPOLINE_AMD ( 7*32+13) /* AMD Retpoline mitigation for Spectre variant 2 */
#define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */ #define X86_FEATURE_INTEL_PPIN ( 7*32+14) /* Intel Processor Inventory Number */
#define X86_FEATURE_CDP_L2 ( 7*32+15) /* Code and Data Prioritization L2 */
#define X86_FEATURE_AVX512_4VNNIW ( 7*32+16) /* AVX-512 Neural Network Instructions */ #define X86_FEATURE_AVX512_4VNNIW ( 7*32+16) /* AVX-512 Neural Network Instructions */
#define X86_FEATURE_AVX512_4FMAPS ( 7*32+17) /* AVX-512 Multiply Accumulation Single precision */ #define X86_FEATURE_AVX512_4FMAPS ( 7*32+17) /* AVX-512 Multiply Accumulation Single precision */
......
...@@ -135,6 +135,40 @@ struct rdt_resource rdt_resources_all[] = { ...@@ -135,6 +135,40 @@ struct rdt_resource rdt_resources_all[] = {
.format_str = "%d=%0*x", .format_str = "%d=%0*x",
.fflags = RFTYPE_RES_CACHE, .fflags = RFTYPE_RES_CACHE,
}, },
[RDT_RESOURCE_L2DATA] =
{
.rid = RDT_RESOURCE_L2DATA,
.name = "L2DATA",
.domains = domain_init(RDT_RESOURCE_L2DATA),
.msr_base = IA32_L2_CBM_BASE,
.msr_update = cat_wrmsr,
.cache_level = 2,
.cache = {
.min_cbm_bits = 1,
.cbm_idx_mult = 2,
.cbm_idx_offset = 0,
},
.parse_ctrlval = parse_cbm,
.format_str = "%d=%0*x",
.fflags = RFTYPE_RES_CACHE,
},
[RDT_RESOURCE_L2CODE] =
{
.rid = RDT_RESOURCE_L2CODE,
.name = "L2CODE",
.domains = domain_init(RDT_RESOURCE_L2CODE),
.msr_base = IA32_L2_CBM_BASE,
.msr_update = cat_wrmsr,
.cache_level = 2,
.cache = {
.min_cbm_bits = 1,
.cbm_idx_mult = 2,
.cbm_idx_offset = 1,
},
.parse_ctrlval = parse_cbm,
.format_str = "%d=%0*x",
.fflags = RFTYPE_RES_CACHE,
},
[RDT_RESOURCE_MBA] = [RDT_RESOURCE_MBA] =
{ {
.rid = RDT_RESOURCE_MBA, .rid = RDT_RESOURCE_MBA,
...@@ -259,15 +293,15 @@ static void rdt_get_cache_alloc_cfg(int idx, struct rdt_resource *r) ...@@ -259,15 +293,15 @@ static void rdt_get_cache_alloc_cfg(int idx, struct rdt_resource *r)
r->alloc_enabled = true; r->alloc_enabled = true;
} }
static void rdt_get_cdp_l3_config(int type) static void rdt_get_cdp_config(int level, int type)
{ {
struct rdt_resource *r_l3 = &rdt_resources_all[RDT_RESOURCE_L3]; struct rdt_resource *r_l = &rdt_resources_all[level];
struct rdt_resource *r = &rdt_resources_all[type]; struct rdt_resource *r = &rdt_resources_all[type];
r->num_closid = r_l3->num_closid / 2; r->num_closid = r_l->num_closid / 2;
r->cache.cbm_len = r_l3->cache.cbm_len; r->cache.cbm_len = r_l->cache.cbm_len;
r->default_ctrl = r_l3->default_ctrl; r->default_ctrl = r_l->default_ctrl;
r->cache.shareable_bits = r_l3->cache.shareable_bits; r->cache.shareable_bits = r_l->cache.shareable_bits;
r->data_width = (r->cache.cbm_len + 3) / 4; r->data_width = (r->cache.cbm_len + 3) / 4;
r->alloc_capable = true; r->alloc_capable = true;
/* /*
...@@ -277,6 +311,18 @@ static void rdt_get_cdp_l3_config(int type) ...@@ -277,6 +311,18 @@ static void rdt_get_cdp_l3_config(int type)
r->alloc_enabled = false; r->alloc_enabled = false;
} }
static void rdt_get_cdp_l3_config(void)
{
rdt_get_cdp_config(RDT_RESOURCE_L3, RDT_RESOURCE_L3DATA);
rdt_get_cdp_config(RDT_RESOURCE_L3, RDT_RESOURCE_L3CODE);
}
static void rdt_get_cdp_l2_config(void)
{
rdt_get_cdp_config(RDT_RESOURCE_L2, RDT_RESOURCE_L2DATA);
rdt_get_cdp_config(RDT_RESOURCE_L2, RDT_RESOURCE_L2CODE);
}
static int get_cache_id(int cpu, int level) static int get_cache_id(int cpu, int level)
{ {
struct cpu_cacheinfo *ci = get_cpu_cacheinfo(cpu); struct cpu_cacheinfo *ci = get_cpu_cacheinfo(cpu);
...@@ -645,6 +691,7 @@ enum { ...@@ -645,6 +691,7 @@ enum {
RDT_FLAG_L3_CAT, RDT_FLAG_L3_CAT,
RDT_FLAG_L3_CDP, RDT_FLAG_L3_CDP,
RDT_FLAG_L2_CAT, RDT_FLAG_L2_CAT,
RDT_FLAG_L2_CDP,
RDT_FLAG_MBA, RDT_FLAG_MBA,
}; };
...@@ -667,6 +714,7 @@ static struct rdt_options rdt_options[] __initdata = { ...@@ -667,6 +714,7 @@ static struct rdt_options rdt_options[] __initdata = {
RDT_OPT(RDT_FLAG_L3_CAT, "l3cat", X86_FEATURE_CAT_L3), RDT_OPT(RDT_FLAG_L3_CAT, "l3cat", X86_FEATURE_CAT_L3),
RDT_OPT(RDT_FLAG_L3_CDP, "l3cdp", X86_FEATURE_CDP_L3), RDT_OPT(RDT_FLAG_L3_CDP, "l3cdp", X86_FEATURE_CDP_L3),
RDT_OPT(RDT_FLAG_L2_CAT, "l2cat", X86_FEATURE_CAT_L2), RDT_OPT(RDT_FLAG_L2_CAT, "l2cat", X86_FEATURE_CAT_L2),
RDT_OPT(RDT_FLAG_L2_CDP, "l2cdp", X86_FEATURE_CDP_L2),
RDT_OPT(RDT_FLAG_MBA, "mba", X86_FEATURE_MBA), RDT_OPT(RDT_FLAG_MBA, "mba", X86_FEATURE_MBA),
}; };
#define NUM_RDT_OPTIONS ARRAY_SIZE(rdt_options) #define NUM_RDT_OPTIONS ARRAY_SIZE(rdt_options)
...@@ -729,15 +777,15 @@ static __init bool get_rdt_alloc_resources(void) ...@@ -729,15 +777,15 @@ static __init bool get_rdt_alloc_resources(void)
if (rdt_cpu_has(X86_FEATURE_CAT_L3)) { if (rdt_cpu_has(X86_FEATURE_CAT_L3)) {
rdt_get_cache_alloc_cfg(1, &rdt_resources_all[RDT_RESOURCE_L3]); rdt_get_cache_alloc_cfg(1, &rdt_resources_all[RDT_RESOURCE_L3]);
if (rdt_cpu_has(X86_FEATURE_CDP_L3)) { if (rdt_cpu_has(X86_FEATURE_CDP_L3))
rdt_get_cdp_l3_config(RDT_RESOURCE_L3DATA); rdt_get_cdp_l3_config();
rdt_get_cdp_l3_config(RDT_RESOURCE_L3CODE);
}
ret = true; ret = true;
} }
if (rdt_cpu_has(X86_FEATURE_CAT_L2)) { if (rdt_cpu_has(X86_FEATURE_CAT_L2)) {
/* CPUID 0x10.2 fields are same format at 0x10.1 */ /* CPUID 0x10.2 fields are same format at 0x10.1 */
rdt_get_cache_alloc_cfg(2, &rdt_resources_all[RDT_RESOURCE_L2]); rdt_get_cache_alloc_cfg(2, &rdt_resources_all[RDT_RESOURCE_L2]);
if (rdt_cpu_has(X86_FEATURE_CDP_L2))
rdt_get_cdp_l2_config();
ret = true; ret = true;
} }
......
...@@ -7,12 +7,15 @@ ...@@ -7,12 +7,15 @@
#include <linux/jump_label.h> #include <linux/jump_label.h>
#define IA32_L3_QOS_CFG 0xc81 #define IA32_L3_QOS_CFG 0xc81
#define IA32_L2_QOS_CFG 0xc82
#define IA32_L3_CBM_BASE 0xc90 #define IA32_L3_CBM_BASE 0xc90
#define IA32_L2_CBM_BASE 0xd10 #define IA32_L2_CBM_BASE 0xd10
#define IA32_MBA_THRTL_BASE 0xd50 #define IA32_MBA_THRTL_BASE 0xd50
#define L3_QOS_CDP_ENABLE 0x01ULL #define L3_QOS_CDP_ENABLE 0x01ULL
#define L2_QOS_CDP_ENABLE 0x01ULL
/* /*
* Event IDs are used to program IA32_QM_EVTSEL before reading event * Event IDs are used to program IA32_QM_EVTSEL before reading event
* counter from IA32_QM_CTR * counter from IA32_QM_CTR
...@@ -357,6 +360,8 @@ enum { ...@@ -357,6 +360,8 @@ enum {
RDT_RESOURCE_L3DATA, RDT_RESOURCE_L3DATA,
RDT_RESOURCE_L3CODE, RDT_RESOURCE_L3CODE,
RDT_RESOURCE_L2, RDT_RESOURCE_L2,
RDT_RESOURCE_L2DATA,
RDT_RESOURCE_L2CODE,
RDT_RESOURCE_MBA, RDT_RESOURCE_MBA,
/* Must be the last */ /* Must be the last */
......
...@@ -990,6 +990,7 @@ mongroup_create_dir(struct kernfs_node *parent_kn, struct rdtgroup *prgrp, ...@@ -990,6 +990,7 @@ mongroup_create_dir(struct kernfs_node *parent_kn, struct rdtgroup *prgrp,
kernfs_remove(kn); kernfs_remove(kn);
return ret; return ret;
} }
static void l3_qos_cfg_update(void *arg) static void l3_qos_cfg_update(void *arg)
{ {
bool *enable = arg; bool *enable = arg;
...@@ -997,8 +998,17 @@ static void l3_qos_cfg_update(void *arg) ...@@ -997,8 +998,17 @@ static void l3_qos_cfg_update(void *arg)
wrmsrl(IA32_L3_QOS_CFG, *enable ? L3_QOS_CDP_ENABLE : 0ULL); wrmsrl(IA32_L3_QOS_CFG, *enable ? L3_QOS_CDP_ENABLE : 0ULL);
} }
static int set_l3_qos_cfg(struct rdt_resource *r, bool enable) static void l2_qos_cfg_update(void *arg)
{ {
bool *enable = arg;
wrmsrl(IA32_L2_QOS_CFG, *enable ? L2_QOS_CDP_ENABLE : 0ULL);
}
static int set_cache_qos_cfg(int level, bool enable)
{
void (*update)(void *arg);
struct rdt_resource *r_l;
cpumask_var_t cpu_mask; cpumask_var_t cpu_mask;
struct rdt_domain *d; struct rdt_domain *d;
int cpu; int cpu;
...@@ -1006,16 +1016,24 @@ static int set_l3_qos_cfg(struct rdt_resource *r, bool enable) ...@@ -1006,16 +1016,24 @@ static int set_l3_qos_cfg(struct rdt_resource *r, bool enable)
if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL)) if (!zalloc_cpumask_var(&cpu_mask, GFP_KERNEL))
return -ENOMEM; return -ENOMEM;
list_for_each_entry(d, &r->domains, list) { if (level == RDT_RESOURCE_L3)
update = l3_qos_cfg_update;
else if (level == RDT_RESOURCE_L2)
update = l2_qos_cfg_update;
else
return -EINVAL;
r_l = &rdt_resources_all[level];
list_for_each_entry(d, &r_l->domains, list) {
/* Pick one CPU from each domain instance to update MSR */ /* Pick one CPU from each domain instance to update MSR */
cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask); cpumask_set_cpu(cpumask_any(&d->cpu_mask), cpu_mask);
} }
cpu = get_cpu(); cpu = get_cpu();
/* Update QOS_CFG MSR on this cpu if it's in cpu_mask. */ /* Update QOS_CFG MSR on this cpu if it's in cpu_mask. */
if (cpumask_test_cpu(cpu, cpu_mask)) if (cpumask_test_cpu(cpu, cpu_mask))
l3_qos_cfg_update(&enable); update(&enable);
/* Update QOS_CFG MSR on all other cpus in cpu_mask. */ /* Update QOS_CFG MSR on all other cpus in cpu_mask. */
smp_call_function_many(cpu_mask, l3_qos_cfg_update, &enable, 1); smp_call_function_many(cpu_mask, update, &enable, 1);
put_cpu(); put_cpu();
free_cpumask_var(cpu_mask); free_cpumask_var(cpu_mask);
...@@ -1023,52 +1041,99 @@ static int set_l3_qos_cfg(struct rdt_resource *r, bool enable) ...@@ -1023,52 +1041,99 @@ static int set_l3_qos_cfg(struct rdt_resource *r, bool enable)
return 0; return 0;
} }
static int cdp_enable(void) static int cdp_enable(int level, int data_type, int code_type)
{ {
struct rdt_resource *r_l3data = &rdt_resources_all[RDT_RESOURCE_L3DATA]; struct rdt_resource *r_ldata = &rdt_resources_all[data_type];
struct rdt_resource *r_l3code = &rdt_resources_all[RDT_RESOURCE_L3CODE]; struct rdt_resource *r_lcode = &rdt_resources_all[code_type];
struct rdt_resource *r_l3 = &rdt_resources_all[RDT_RESOURCE_L3]; struct rdt_resource *r_l = &rdt_resources_all[level];
int ret; int ret;
if (!r_l3->alloc_capable || !r_l3data->alloc_capable || if (!r_l->alloc_capable || !r_ldata->alloc_capable ||
!r_l3code->alloc_capable) !r_lcode->alloc_capable)
return -EINVAL; return -EINVAL;
ret = set_l3_qos_cfg(r_l3, true); ret = set_cache_qos_cfg(level, true);
if (!ret) { if (!ret) {
r_l3->alloc_enabled = false; r_l->alloc_enabled = false;
r_l3data->alloc_enabled = true; r_ldata->alloc_enabled = true;
r_l3code->alloc_enabled = true; r_lcode->alloc_enabled = true;
} }
return ret; return ret;
} }
static void cdp_disable(void) static int cdpl3_enable(void)
{ {
struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3]; return cdp_enable(RDT_RESOURCE_L3, RDT_RESOURCE_L3DATA,
RDT_RESOURCE_L3CODE);
}
static int cdpl2_enable(void)
{
return cdp_enable(RDT_RESOURCE_L2, RDT_RESOURCE_L2DATA,
RDT_RESOURCE_L2CODE);
}
static void cdp_disable(int level, int data_type, int code_type)
{
struct rdt_resource *r = &rdt_resources_all[level];
r->alloc_enabled = r->alloc_capable; r->alloc_enabled = r->alloc_capable;
if (rdt_resources_all[RDT_RESOURCE_L3DATA].alloc_enabled) { if (rdt_resources_all[data_type].alloc_enabled) {
rdt_resources_all[RDT_RESOURCE_L3DATA].alloc_enabled = false; rdt_resources_all[data_type].alloc_enabled = false;
rdt_resources_all[RDT_RESOURCE_L3CODE].alloc_enabled = false; rdt_resources_all[code_type].alloc_enabled = false;
set_l3_qos_cfg(r, false); set_cache_qos_cfg(level, false);
} }
} }
static void cdpl3_disable(void)
{
cdp_disable(RDT_RESOURCE_L3, RDT_RESOURCE_L3DATA, RDT_RESOURCE_L3CODE);
}
static void cdpl2_disable(void)
{
cdp_disable(RDT_RESOURCE_L2, RDT_RESOURCE_L2DATA, RDT_RESOURCE_L2CODE);
}
static void cdp_disable_all(void)
{
if (rdt_resources_all[RDT_RESOURCE_L3DATA].alloc_enabled)
cdpl3_disable();
if (rdt_resources_all[RDT_RESOURCE_L2DATA].alloc_enabled)
cdpl2_disable();
}
static int parse_rdtgroupfs_options(char *data) static int parse_rdtgroupfs_options(char *data)
{ {
char *token, *o = data; char *token, *o = data;
int ret = 0; int ret = 0;
while ((token = strsep(&o, ",")) != NULL) { while ((token = strsep(&o, ",")) != NULL) {
if (!*token) if (!*token) {
return -EINVAL; ret = -EINVAL;
goto out;
}
if (!strcmp(token, "cdp")) if (!strcmp(token, "cdp")) {
ret = cdp_enable(); ret = cdpl3_enable();
if (ret)
goto out;
} else if (!strcmp(token, "cdpl2")) {
ret = cdpl2_enable();
if (ret)
goto out;
} else {
ret = -EINVAL;
goto out;
}
} }
return 0;
out:
pr_err("Invalid mount option \"%s\"\n", token);
return ret; return ret;
} }
...@@ -1223,7 +1288,7 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type, ...@@ -1223,7 +1288,7 @@ static struct dentry *rdt_mount(struct file_system_type *fs_type,
out_info: out_info:
kernfs_remove(kn_info); kernfs_remove(kn_info);
out_cdp: out_cdp:
cdp_disable(); cdp_disable_all();
out: out:
rdt_last_cmd_clear(); rdt_last_cmd_clear();
mutex_unlock(&rdtgroup_mutex); mutex_unlock(&rdtgroup_mutex);
...@@ -1383,7 +1448,7 @@ static void rdt_kill_sb(struct super_block *sb) ...@@ -1383,7 +1448,7 @@ static void rdt_kill_sb(struct super_block *sb)
/*Put everything back to default values. */ /*Put everything back to default values. */
for_each_alloc_enabled_rdt_resource(r) for_each_alloc_enabled_rdt_resource(r)
reset_all_ctrls(r); reset_all_ctrls(r);
cdp_disable(); cdp_disable_all();
rmdir_all_sub(); rmdir_all_sub();
static_branch_disable_cpuslocked(&rdt_alloc_enable_key); static_branch_disable_cpuslocked(&rdt_alloc_enable_key);
static_branch_disable_cpuslocked(&rdt_mon_enable_key); static_branch_disable_cpuslocked(&rdt_mon_enable_key);
......
...@@ -26,6 +26,7 @@ static const struct cpuid_bit cpuid_bits[] = { ...@@ -26,6 +26,7 @@ static const struct cpuid_bit cpuid_bits[] = {
{ X86_FEATURE_CAT_L3, CPUID_EBX, 1, 0x00000010, 0 }, { X86_FEATURE_CAT_L3, CPUID_EBX, 1, 0x00000010, 0 },
{ X86_FEATURE_CAT_L2, CPUID_EBX, 2, 0x00000010, 0 }, { X86_FEATURE_CAT_L2, CPUID_EBX, 2, 0x00000010, 0 },
{ X86_FEATURE_CDP_L3, CPUID_ECX, 2, 0x00000010, 1 }, { X86_FEATURE_CDP_L3, CPUID_ECX, 2, 0x00000010, 1 },
{ X86_FEATURE_CDP_L2, CPUID_ECX, 2, 0x00000010, 2 },
{ X86_FEATURE_MBA, CPUID_EBX, 3, 0x00000010, 0 }, { X86_FEATURE_MBA, CPUID_EBX, 3, 0x00000010, 0 },
{ X86_FEATURE_HW_PSTATE, CPUID_EDX, 7, 0x80000007, 0 }, { X86_FEATURE_HW_PSTATE, CPUID_EDX, 7, 0x80000007, 0 },
{ X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 }, { X86_FEATURE_CPB, CPUID_EDX, 9, 0x80000007, 0 },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment