From: Wang ShaoBo bobo.shaobowang@huawei.com
hulk inclusion category: feature bugzilla: 34278 CVE: NA
-------------------------------------------------
Currently configuration control type is devided into three classes: COMMON, PRIORITY and HARDLIMIT, capacities' features for mount options is stored in ctrl_extend_bits field live in resctrl resource structure to figure out which configuration type is allowed to apply, when writing schemata sysfile, all related configurations' content from corresponding configuration array will be updated and applied once time.
we can set configuration like this: e.g. > mount -t resctrl resctrl /sys/fs/resctrl && cd /sys/fs/resctrl -o hardlimit > cat schemata L3:0=7fff;1=7fff;2=7fff;3=7fff MB:0=100;1=100;2=100;3=100 MBHDL:0=1;1=1;2=1;3=1 > echo 'MB:0=10' > schemata && echo 'MBHDL:0=0' > schemata # no hardlimit
This also deletes opt_list no longer needed that used as organizing different control types, now we can check supports from ctrl_extend_bits and do extended control-type works by schema list.
Signed-off-by: Wang ShaoBo bobo.shaobowang@huawei.com Reviewed-by: Xiongfeng Wang wangxiongfeng2@huawei.com Reviewed-by: Cheng Jian cj.chengjian@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- arch/arm64/include/asm/mpam.h | 37 ++- arch/arm64/include/asm/mpam_resource.h | 2 + arch/arm64/kernel/mpam/mpam_ctrlmon.c | 206 +++++++++++----- arch/arm64/kernel/mpam/mpam_resctrl.c | 312 +++++++++++++++++++------ arch/arm64/kernel/mpam/mpam_setup.c | 37 ++- include/linux/resctrlfs.h | 6 +- 6 files changed, 455 insertions(+), 145 deletions(-)
diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h index 5a76fb5d0fc6..6641180b4c3a 100644 --- a/arch/arm64/include/asm/mpam.h +++ b/arch/arm64/include/asm/mpam.h @@ -117,6 +117,21 @@ DECLARE_STATIC_KEY_FALSE(resctrl_mon_enable_key);
extern int max_name_width, max_data_width;
+enum resctrl_ctrl_type { + SCHEMA_COMM = 0, + SCHEMA_PRI, + SCHEMA_HDL, + SCHEMA_NUM_CTRL_TYPE +}; + +#define for_each_ctrl_type(t) \ + for (t = SCHEMA_COMM; t != SCHEMA_NUM_CTRL_TYPE; t++) + +#define for_each_extend_ctrl_type(t) \ + for (t = SCHEMA_PRI; t != SCHEMA_NUM_CTRL_TYPE; t++) + +bool resctrl_ctrl_extend_bits_match(u32 bitmap, enum resctrl_ctrl_type type); + enum resctrl_conf_type { CDP_BOTH = 0, CDP_CODE, @@ -183,25 +198,34 @@ do { \ */ struct resctrl_staged_config { hw_closid_t hw_closid; - u32 new_ctrl; + u32 new_ctrl[SCHEMA_NUM_CTRL_TYPE]; bool have_new_ctrl; enum resctrl_conf_type conf_type; + enum resctrl_ctrl_type ctrl_type; };
/* later move to resctrl common directory */ -#define RESCTRL_NAME_LEN 7 +#define RESCTRL_NAME_LEN 15 + +struct resctrl_schema_ctrl { + struct list_head list; + char name[RESCTRL_NAME_LEN]; + enum resctrl_ctrl_type ctrl_type; +};
/** * @list: Member of resctrl's schema list * @name: Name visible in the schemata file * @conf_type: Type of configuration, e.g. code/data/both * @res: The rdt_resource for this entry + * @schemata_ctrl_list: Type of ctrl configuration. e.g. priority/hardlimit */ struct resctrl_schema { struct list_head list; char name[RESCTRL_NAME_LEN]; enum resctrl_conf_type conf_type; struct resctrl_resource *res; + struct list_head schema_ctrl_list; };
/** @@ -230,8 +254,7 @@ struct rdt_domain { void __iomem *base;
/* arch specific fields */ - u32 *ctrl_val; - u32 new_ctrl; + u32 *ctrl_val[SCHEMA_NUM_CTRL_TYPE]; bool have_new_ctrl;
/* for debug */ @@ -260,6 +283,7 @@ void post_resctrl_mount(void); struct sd_closid;
struct msr_param { + enum resctrl_ctrl_type type; struct sd_closid *closid; };
@@ -295,13 +319,14 @@ struct raw_resctrl_resource { u16 hdl_wd;
void (*msr_update)(struct resctrl_resource *r, struct rdt_domain *d, - struct list_head *opt_list, struct msr_param *para); + struct msr_param *para); u64 (*msr_read)(struct rdt_domain *d, struct msr_param *para);
int data_width; const char *format_str; int (*parse_ctrlval)(char *buf, struct raw_resctrl_resource *r, - struct resctrl_staged_config *cfg); + struct resctrl_staged_config *cfg, + enum resctrl_ctrl_type ctrl_type);
u16 num_mon; u64 (*mon_read)(struct rdt_domain *d, void *md_priv); diff --git a/arch/arm64/include/asm/mpam_resource.h b/arch/arm64/include/asm/mpam_resource.h index cc863183e1be..8868da13411b 100644 --- a/arch/arm64/include/asm/mpam_resource.h +++ b/arch/arm64/include/asm/mpam_resource.h @@ -76,6 +76,7 @@ #define MBW_MAX_SET(v) (MBW_MAX_HARDLIM|((v) << (16 - BWA_WD))) #define MBW_MAX_GET(v) (((v) & MBW_MAX_MASK) >> (16 - BWA_WD)) #define MBW_MAX_SET_HDL(r) (r | MBW_MAX_HARDLIM) +#define MBW_MAX_GET_HDL(r) (r & MBW_MAX_HARDLIM) /* MPAMCFG_MBW_PROP */ #define MBW_PROP_HARDLIM BIT(31) #define MBW_PROP_SET_HDL(r) (r | MBW_PROP_HARDLIM) @@ -133,6 +134,7 @@ * MPAMCFG_MBW_MAX SET - temp Hard code */ #define MPAMCFG_PRI_DSPRI_SHIFT 16 +#define MPAMCFG_PRI_GET(r) ((r & GENMASK(15, 0)) | (r & GENMASK(16, 31)) >> 16)
/* MPAMF_PRI_IDR - MPAM features priority partitioning ID register */ #define MPAMF_PRI_IDR_HAS_INTPRI BIT(0) diff --git a/arch/arm64/kernel/mpam/mpam_ctrlmon.c b/arch/arm64/kernel/mpam/mpam_ctrlmon.c index 47ebb64ccbe1..b7dc8226a008 100644 --- a/arch/arm64/kernel/mpam/mpam_ctrlmon.c +++ b/arch/arm64/kernel/mpam/mpam_ctrlmon.c @@ -39,8 +39,15 @@ LIST_HEAD(resctrl_all_schema); /* Init schemata content */ static int add_schema(enum resctrl_conf_type t, struct resctrl_resource *r) { + int ret = 0; char *suffix = ""; + char *ctrl_suffix = ""; struct resctrl_schema *s; + struct raw_resctrl_resource *rr; + struct resctrl_schema_ctrl *sc, *sc_tmp; + struct resctrl_schema_ctrl *sc_pri = NULL; + struct resctrl_schema_ctrl *sc_hdl = NULL; + enum resctrl_ctrl_type type;
s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) @@ -69,7 +76,50 @@ static int add_schema(enum resctrl_conf_type t, struct resctrl_resource *r) INIT_LIST_HEAD(&s->list); list_add_tail(&s->list, &resctrl_all_schema);
+ /* + * Initialize extension ctrl type with MPAM capabilities, + * e.g. priority/hardlimit. + */ + rr = r->res; + INIT_LIST_HEAD(&s->schema_ctrl_list); + for_each_extend_ctrl_type(type) { + if ((type == SCHEMA_PRI && !rr->pri_wd) || + (type == SCHEMA_HDL && !rr->hdl_wd) || + !resctrl_ctrl_extend_bits_match(r->ctrl_extend_bits, + type)) + continue; + + sc = kzalloc(sizeof(*sc), GFP_KERNEL); + if (!sc) { + ret = -ENOMEM; + goto err; + } + sc->ctrl_type = type; + if (type == SCHEMA_PRI) { + sc_pri = sc; + ctrl_suffix = "PRI"; + } else if (type == SCHEMA_HDL) { + sc_hdl = sc; + ctrl_suffix = "HDL"; + } + + WARN_ON_ONCE(strlen(r->name) + strlen(suffix) + + strlen(ctrl_suffix) + 1 > RESCTRL_NAME_LEN); + snprintf(sc->name, sizeof(sc->name), "%s%s%s", + r->name, suffix, ctrl_suffix); + list_add_tail(&sc->list, &s->schema_ctrl_list); + } + return 0; + +err: + list_for_each_entry_safe(sc, sc_tmp, &s->schema_ctrl_list, list) { + list_del(&sc->list); + kfree(sc); + } + list_del(&s->list); + kfree(s); + return ret; }
int schemata_list_init(void) @@ -104,69 +154,88 @@ int schemata_list_init(void) void schemata_list_destroy(void) { struct resctrl_schema *s, *tmp; + struct resctrl_schema_ctrl *sc, *sc_tmp;
list_for_each_entry_safe(s, tmp, &resctrl_all_schema, list) { + list_for_each_entry_safe(sc, sc_tmp, &s->schema_ctrl_list, list) { + list_del(&sc->list); + kfree(sc); + } list_del(&s->list); kfree(s); } }
-static int resctrl_group_update_domains(struct rdtgroup *rdtgrp, - struct resctrl_resource *r) +static void resctrl_group_update_domain_ctrls(struct rdtgroup *rdtgrp, + struct resctrl_resource *r, struct rdt_domain *dom) { int i; - struct rdt_domain *d; - struct raw_resctrl_resource *rr; struct resctrl_staged_config *cfg; + enum resctrl_ctrl_type type; hw_closid_t hw_closid; + struct raw_resctrl_resource *rr; struct sd_closid closid; struct list_head *head; struct rdtgroup *entry; struct msr_param para;
- para.closid = &closid; + bool update_on;
rr = r->res; - list_for_each_entry(d, &r->domains, list) { - cfg = d->staged_cfg; - for (i = 0; i < ARRAY_SIZE(d->staged_cfg); i++) { - if (!cfg[i].have_new_ctrl) - continue;
- /* - * for ctrl group configuration, hw_closid of cfg[i] - * equals to rdtgrp->closid.intpartid. - */ - closid.intpartid = hw_closid_val(cfg[i].hw_closid); + cfg = dom->staged_cfg; + para.closid = &closid;
+ for (i = 0; i < ARRAY_SIZE(dom->staged_cfg); i++) { + if (!cfg[i].have_new_ctrl) + continue; + update_on = false; + /* + * for ctrl group configuration, hw_closid of cfg[i] equals + * to rdtgrp->closid.intpartid. + */ + closid.intpartid = hw_closid_val(cfg[i].hw_closid); + for_each_ctrl_type(type) { /* if ctrl group's config has changed, refresh it first. */ - if (d->ctrl_val[closid.intpartid] != cfg[i].new_ctrl) { + if (dom->ctrl_val[closid.intpartid] != cfg[i].new_ctrl) { /* * duplicate ctrl group's configuration indexed * by intpartid from domain ctrl_val array. */ resctrl_cdp_map(clos, rdtgrp->closid.reqpartid, - cfg[i].conf_type, hw_closid); - closid.reqpartid = hw_closid_val(hw_closid); - - d->ctrl_val[closid.intpartid] = cfg[i].new_ctrl; - d->have_new_ctrl = true; - rr->msr_update(r, d, NULL, ¶); - } - /* - * we should synchronize all child mon groups' - * configuration from this ctrl rdtgrp - */ - head = &rdtgrp->mon.crdtgrp_list; - list_for_each_entry(entry, head, mon.crdtgrp_list) { - resctrl_cdp_map(clos, entry->closid.reqpartid, cfg[i].conf_type, hw_closid); closid.reqpartid = hw_closid_val(hw_closid);
- rr->msr_update(r, d, NULL, ¶); + dom->ctrl_val[type][closid.intpartid] = + cfg[i].new_ctrl[type]; + dom->have_new_ctrl = true; + update_on = true; } } + if (update_on) + rr->msr_update(r, dom, ¶); + + /* + * we should synchronize all child mon groups' + * configuration from this ctrl rdtgrp + */ + head = &rdtgrp->mon.crdtgrp_list; + list_for_each_entry(entry, head, mon.crdtgrp_list) { + resctrl_cdp_map(clos, entry->closid.reqpartid, + cfg[i].conf_type, hw_closid); + closid.reqpartid = hw_closid_val(hw_closid); + rr->msr_update(r, dom, ¶); + } } +} + +static int resctrl_group_update_domains(struct rdtgroup *rdtgrp, + struct resctrl_resource *r) +{ + struct rdt_domain *d; + + list_for_each_entry(d, &r->domains, list) + resctrl_group_update_domain_ctrls(rdtgrp, r, d);
return 0; } @@ -177,8 +246,10 @@ static int resctrl_group_update_domains(struct rdtgroup *rdtgrp, * separated by ";". The "id" is in decimal, and must match one of * the "id"s for this resource. */ -static int parse_line(char *line, struct resctrl_resource *r, - enum resctrl_conf_type t, u32 closid) +static int +parse_line(char *line, struct resctrl_resource *r, + enum resctrl_conf_type conf_type, + enum resctrl_ctrl_type ctrl_type, u32 closid) { struct raw_resctrl_resource *rr = r->res; char *dom = NULL; @@ -199,11 +270,13 @@ static int parse_line(char *line, struct resctrl_resource *r, dom = strim(dom); list_for_each_entry(d, &r->domains, list) { if (d->id == dom_id) { - resctrl_cdp_map(clos, closid, t, hw_closid); - if (rr->parse_ctrlval(dom, rr, &d->staged_cfg[t])) + resctrl_cdp_map(clos, closid, conf_type, hw_closid); + if (rr->parse_ctrlval(dom, rr, + &d->staged_cfg[conf_type], ctrl_type)) return -EINVAL; - d->staged_cfg[t].hw_closid = hw_closid; - d->staged_cfg[t].conf_type = t; + d->staged_cfg[conf_type].hw_closid = hw_closid; + d->staged_cfg[conf_type].conf_type = conf_type; + d->staged_cfg[conf_type].ctrl_type = ctrl_type; goto next; } } @@ -216,6 +289,7 @@ resctrl_group_parse_schema_resource(char *resname, char *tok, u32 closid) struct resctrl_resource *r; struct resctrl_schema *s; enum resctrl_conf_type t; + struct resctrl_schema_ctrl *sc;
list_for_each_entry(s, &resctrl_all_schema, list) { r = s->res; @@ -224,10 +298,18 @@ resctrl_group_parse_schema_resource(char *resname, char *tok, u32 closid) continue;
if (r->alloc_enabled) { - if (!strcmp(resname, s->name) && - closid < mpam_sysprops_num_partid()) { - t = conf_name_to_conf_type(s->name); - return parse_line(tok, r, t, closid); + if (closid >= mpam_sysprops_num_partid()) + continue; + t = conf_name_to_conf_type(s->name); + if (!strcmp(resname, s->name)) + return parse_line(tok, r, t, + SCHEMA_COMM, closid); + + list_for_each_entry(sc, &s->schema_ctrl_list, list) { + if (!strcmp(resname, sc->name)) + return parse_line(tok, r, t, + sc->ctrl_type, + closid); } } } @@ -312,7 +394,8 @@ ssize_t resctrl_group_schemata_write(struct kernfs_open_file *of, * a single "S" simply. */ static void show_doms(struct seq_file *s, struct resctrl_resource *r, - char *schema_name, struct sd_closid *closid) + char *schema_name, enum resctrl_ctrl_type type, + struct sd_closid *closid) { struct raw_resctrl_resource *rr = r->res; struct rdt_domain *dom; @@ -323,6 +406,7 @@ static void show_doms(struct seq_file *s, struct resctrl_resource *r, u32 reg_val;
para.closid = closid; + para.type = type;
if (r->dom_num > RESCTRL_SHOW_DOM_MAX_NUM) rg = true; @@ -331,13 +415,13 @@ static void show_doms(struct seq_file *s, struct resctrl_resource *r, list_for_each_entry(dom, &r->domains, list) { reg_val = rr->msr_read(dom, ¶);
- if (rg && reg_val == r->default_ctrl && + if (rg && reg_val == r->default_ctrl[SCHEMA_COMM] && prev_auto_fill == true) continue;
if (sep) seq_puts(s, ";"); - if (rg && reg_val == r->default_ctrl) { + if (rg && reg_val == r->default_ctrl[SCHEMA_COMM]) { prev_auto_fill = true; seq_puts(s, "S"); } else { @@ -358,6 +442,7 @@ int resctrl_group_schemata_show(struct kernfs_open_file *of, int ret = 0; hw_closid_t hw_closid; struct sd_closid closid; + struct resctrl_schema_ctrl *sc;
rdtgrp = resctrl_group_kn_lock_live(of->kn); if (rdtgrp) { @@ -374,7 +459,10 @@ int resctrl_group_schemata_show(struct kernfs_open_file *of, rs->conf_type, hw_closid); closid.reqpartid = hw_closid_val(hw_closid);
- show_doms(s, r, rs->name, &closid); + show_doms(s, r, rs->name, SCHEMA_COMM, &closid); + list_for_each_entry(sc, &rs->schema_ctrl_list, list) { + show_doms(s, r, sc->name, sc->ctrl_type, &closid); + } } } } else { @@ -600,12 +688,17 @@ static void rdtgroup_init_mba(struct resctrl_resource *r, u32 closid) { struct resctrl_staged_config *cfg; struct rdt_domain *d; + enum resctrl_ctrl_type t;
list_for_each_entry(d, &r->domains, list) { cfg = &d->staged_cfg[CDP_BOTH]; - cfg->new_ctrl = r->default_ctrl; + cfg->new_ctrl[SCHEMA_COMM] = r->default_ctrl[SCHEMA_COMM]; resctrl_cdp_map(clos, closid, CDP_BOTH, cfg->hw_closid); cfg->have_new_ctrl = true; + /* Set extension ctrl default value, e.g. priority/hardlimit */ + for_each_extend_ctrl_type(t) { + cfg->new_ctrl[t] = r->default_ctrl[t]; + } } }
@@ -622,7 +715,8 @@ static void rdtgroup_init_mba(struct resctrl_resource *r, u32 closid) static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid) { struct resctrl_staged_config *cfg; - enum resctrl_conf_type t = s->conf_type; + enum resctrl_conf_type conf_type = s->conf_type; + enum resctrl_ctrl_type ctrl_type; struct rdt_domain *d; struct resctrl_resource *r; u32 used_b = 0; @@ -634,17 +728,17 @@ static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid) return -EINVAL;
list_for_each_entry(d, &s->res->domains, list) { - cfg = &d->staged_cfg[t]; + cfg = &d->staged_cfg[conf_type]; cfg->have_new_ctrl = false; - cfg->new_ctrl = r->cache.shareable_bits; + cfg->new_ctrl[SCHEMA_COMM] = r->cache.shareable_bits; used_b = r->cache.shareable_bits;
unused_b = used_b ^ (BIT_MASK(r->cache.cbm_len) - 1); unused_b &= BIT_MASK(r->cache.cbm_len) - 1; - cfg->new_ctrl |= unused_b; + cfg->new_ctrl[SCHEMA_COMM] |= unused_b;
/* Ensure cbm does not access out-of-bound */ - tmp_cbm = cfg->new_ctrl; + tmp_cbm = cfg->new_ctrl[SCHEMA_COMM]; if (bitmap_weight(&tmp_cbm, r->cache.cbm_len) < r->cache.min_cbm_bits) { rdt_last_cmd_printf("No space on %s:%d\n", @@ -652,8 +746,16 @@ static int rdtgroup_init_cat(struct resctrl_schema *s, u32 closid) return -ENOSPC; }
- resctrl_cdp_map(clos, closid, t, cfg->hw_closid); + resctrl_cdp_map(clos, closid, conf_type, cfg->hw_closid); cfg->have_new_ctrl = true; + + /* + * Set extension ctrl default value, e.g. priority/hardlimit + * with MPAM capabilities. + */ + for_each_extend_ctrl_type(ctrl_type) { + cfg->new_ctrl[ctrl_type] = r->default_ctrl[ctrl_type]; + } }
return 0; diff --git a/arch/arm64/kernel/mpam/mpam_resctrl.c b/arch/arm64/kernel/mpam/mpam_resctrl.c index 6abd682f1fa5..7b986b9c74c4 100644 --- a/arch/arm64/kernel/mpam/mpam_resctrl.c +++ b/arch/arm64/kernel/mpam/mpam_resctrl.c @@ -105,14 +105,29 @@ bool is_resctrl_cdp_enabled(void) return !!resctrl_cdp_enabled; }
+static void +resctrl_ctrl_extend_bits_set(u32 *bitmap, enum resctrl_ctrl_type type) +{ + *bitmap |= BIT(type); +} + +static void resctrl_ctrl_extend_bits_clear(u32 *bitmap) +{ + *bitmap = 0; +} + +bool resctrl_ctrl_extend_bits_match(u32 bitmap, enum resctrl_ctrl_type type) +{ + return bitmap & BIT(type); +} + static void mpam_resctrl_update_component_cfg(struct resctrl_resource *r, - struct rdt_domain *d, struct list_head *opt_list, - struct sd_closid *closid); + struct rdt_domain *d, struct sd_closid *closid);
static void common_wrmsr(struct resctrl_resource *r, struct rdt_domain *d, - struct list_head *opt_list, struct msr_param *para); + struct msr_param *para);
static u64 cache_rdmsr(struct rdt_domain *d, struct msr_param *para); static u64 mbw_rdmsr(struct rdt_domain *d, struct msr_param *para); @@ -122,16 +137,16 @@ static u64 mbw_rdmon(struct rdt_domain *d, void *md_priv);
static int common_wrmon(struct rdt_domain *d, void *md_priv);
-static int parse_cbm(char *buf, struct raw_resctrl_resource *r, - struct resctrl_staged_config *cfg); +static int parse_cache(char *buf, struct raw_resctrl_resource *r, + struct resctrl_staged_config *cfg, enum resctrl_ctrl_type ctrl_type); static int parse_bw(char *buf, struct raw_resctrl_resource *r, - struct resctrl_staged_config *cfg); + struct resctrl_staged_config *cfg, enum resctrl_ctrl_type ctrl_type);
struct raw_resctrl_resource raw_resctrl_resources_all[] = { [RDT_RESOURCE_L3] = { .msr_update = common_wrmsr, .msr_read = cache_rdmsr, - .parse_ctrlval = parse_cbm, + .parse_ctrlval = parse_cache, .format_str = "%d=%0*x", .mon_read = cache_rdmon, .mon_write = common_wrmon, @@ -139,7 +154,7 @@ struct raw_resctrl_resource raw_resctrl_resources_all[] = { [RDT_RESOURCE_L2] = { .msr_update = common_wrmsr, .msr_read = cache_rdmsr, - .parse_ctrlval = parse_cbm, + .parse_ctrlval = parse_cache, .format_str = "%d=%0*x", .mon_read = cache_rdmon, .mon_write = common_wrmon, @@ -164,33 +179,13 @@ mpam_get_raw_resctrl_resource(enum resctrl_resource_level level) }
/* - * Check whether a cache bit mask is valid. for arm64 MPAM, - * it seems that there are no restrictions according to MPAM - * spec expect for requiring at least one bit. - */ -static bool cbm_validate(char *buf, unsigned long *data, - struct raw_resctrl_resource *r) -{ - u64 val; - int ret; - - ret = kstrtou64(buf, 16, &val); - if (ret) { - rdt_last_cmd_printf("non-hex character in mask %s\n", buf); - return false; - } - - *data = val; - return true; -} - -/* - * Read one cache bit mask (hex). Check that it is valid for the current + * Read one cache schema row. Check that it is valid for the current * resource type. */ static int -parse_cbm(char *buf, struct raw_resctrl_resource *r, - struct resctrl_staged_config *cfg) +parse_cache(char *buf, struct raw_resctrl_resource *r, + struct resctrl_staged_config *cfg, + enum resctrl_ctrl_type type) { unsigned long data;
@@ -199,10 +194,24 @@ parse_cbm(char *buf, struct raw_resctrl_resource *r, return -EINVAL; }
- if (!cbm_validate(buf, &data, r)) + switch (type) { + case SCHEMA_COMM: + if (kstrtoul(buf, 16, &data)) + return -EINVAL; + break; + case SCHEMA_PRI: + if (kstrtoul(buf, 10, &data)) + return -EINVAL; + break; + case SCHEMA_HDL: + if (kstrtoul(buf, 10, &data)) + return -EINVAL; + break; + default: return -EINVAL; + }
- cfg->new_ctrl = data; + cfg->new_ctrl[type] = data; cfg->have_new_ctrl = true;
return 0; @@ -253,7 +262,8 @@ static bool bw_validate(char *buf, unsigned long *data,
static int parse_bw(char *buf, struct raw_resctrl_resource *r, - struct resctrl_staged_config *cfg) + struct resctrl_staged_config *cfg, + enum resctrl_ctrl_type type) { unsigned long data;
@@ -262,10 +272,24 @@ parse_bw(char *buf, struct raw_resctrl_resource *r, return -EINVAL; }
- if (!bw_validate(buf, &data, r)) + switch (type) { + case SCHEMA_COMM: + if (!bw_validate(buf, &data, r)) + return -EINVAL; + break; + case SCHEMA_PRI: + if (kstrtoul(buf, 10, &data)) + return -EINVAL; + break; + case SCHEMA_HDL: + if (kstrtoul(buf, 10, &data)) + return -EINVAL; + break; + default: return -EINVAL; + }
- cfg->new_ctrl = data; + cfg->new_ctrl[type] = data; cfg->have_new_ctrl = true;
return 0; @@ -273,14 +297,14 @@ parse_bw(char *buf, struct raw_resctrl_resource *r,
static void common_wrmsr(struct resctrl_resource *r, struct rdt_domain *d, - struct list_head *opt_list, struct msr_param *para) + struct msr_param *para) { struct sync_args args; struct mpam_resctrl_dom *dom;
dom = container_of(d, struct mpam_resctrl_dom, resctrl_dom);
- mpam_resctrl_update_component_cfg(r, d, opt_list, para->closid); + mpam_resctrl_update_component_cfg(r, d, para->closid);
/* * so far we have accomplished configuration replication, @@ -297,31 +321,75 @@ static u64 cache_rdmsr(struct rdt_domain *d, struct msr_param *para) struct mpam_resctrl_dom *dom;
args.closid = *para->closid; - args.reg = MPAMCFG_CPBM;
- dom = container_of(d, struct mpam_resctrl_dom, resctrl_dom); + switch (para->type) { + case SCHEMA_COMM: + args.reg = MPAMCFG_CPBM; + break; + case SCHEMA_PRI: + args.reg = MPAMCFG_PRI; + default: + return 0; + }
+ dom = container_of(d, struct mpam_resctrl_dom, resctrl_dom); mpam_component_get_config(dom->comp, &args, &result);
+ switch (para->type) { + case SCHEMA_PRI: + result = MPAMCFG_PRI_GET(result); + break; + default: + break; + } + return result; }
static u64 mbw_rdmsr(struct rdt_domain *d, struct msr_param *para) { - u64 max; u32 result; struct sync_args args; struct mpam_resctrl_dom *dom;
args.closid = *para->closid; - args.reg = MPAMCFG_MBW_MAX;
- dom = container_of(d, struct mpam_resctrl_dom, resctrl_dom); + /* + * software default set memory bandwidth by + * MPAMCFG_MBW_MAX but not MPAMCFG_MBW_PBM. + */ + switch (para->type) { + case SCHEMA_COMM: + args.reg = MPAMCFG_MBW_MAX; + break; + case SCHEMA_HDL: + args.reg = MPAMCFG_MBW_MAX; + break; + case SCHEMA_PRI: + args.reg = MPAMCFG_PRI; + break; + default: + return 0; + }
+ dom = container_of(d, struct mpam_resctrl_dom, resctrl_dom); mpam_component_get_config(dom->comp, &args, &result);
- max = MBW_MAX_GET(result); - return roundup((max * 100) / 64, 5); + switch (para->type) { + case SCHEMA_COMM: + result = roundup((MBW_MAX_GET(result) * 100) / 64, 5); + break; + case SCHEMA_PRI: + result = MPAMCFG_PRI_GET(result); + break; + case SCHEMA_HDL: + result = MBW_MAX_GET_HDL(result); + break; + default: + break; + } + + return result; }
/* @@ -644,6 +712,52 @@ static int cdpl2_enable(void) return try_to_enable_cdp(RDT_RESOURCE_L2); }
+static void basic_ctrl_enable(void) +{ + struct mpam_resctrl_res *res; + struct resctrl_resource *r; + + for_each_supported_resctrl_exports(res) { + r = &res->resctrl_res; + /* At least SCHEMA_COMM is supported */ + resctrl_ctrl_extend_bits_set(&r->ctrl_extend_bits, SCHEMA_COMM); + } +} + +static int extend_ctrl_enable(enum resctrl_ctrl_type type) +{ + bool match = false; + struct resctrl_resource *r; + struct raw_resctrl_resource *rr; + struct mpam_resctrl_res *res; + + for_each_supported_resctrl_exports(res) { + r = &res->resctrl_res; + rr = r->res; + if ((type == SCHEMA_PRI && rr->pri_wd) || + (type == SCHEMA_HDL && rr->hdl_wd)) { + resctrl_ctrl_extend_bits_set(&r->ctrl_extend_bits, type); + match = true; + } + } + + if (!match) + return -EINVAL; + + return 0; +} + +static void extend_ctrl_disable(void) +{ + struct resctrl_resource *r; + struct mpam_resctrl_res *res; + + for_each_supported_resctrl_exports(res) { + r = &res->resctrl_res; + resctrl_ctrl_extend_bits_clear(&r->ctrl_extend_bits); + } +} + int parse_rdtgroupfs_options(char *data) { char *token; @@ -651,6 +765,7 @@ int parse_rdtgroupfs_options(char *data) int ret = 0;
disable_cdp(); + extend_ctrl_disable();
while ((token = strsep(&o, ",")) != NULL) { if (!*token) { @@ -666,12 +781,22 @@ int parse_rdtgroupfs_options(char *data) ret = cdpl2_enable(); if (ret) goto out; + } else if (!strcmp(token, "priority")) { + ret = extend_ctrl_enable(SCHEMA_PRI); + if (ret) + goto out; + } else if (!strcmp(token, "hardlimit")) { + ret = extend_ctrl_enable(SCHEMA_HDL); + if (ret) + goto out; } else { ret = -EINVAL; goto out; } }
+ basic_ctrl_enable(); + return 0;
out: @@ -1422,45 +1547,70 @@ void __mpam_sched_in(void)
static void mpam_update_from_resctrl_cfg(struct mpam_resctrl_res *res, - u32 resctrl_cfg, struct mpam_config *mpam_cfg) + u32 resctrl_cfg, enum resctrl_ctrl_type ctrl_type, + struct mpam_config *mpam_cfg) { - if (res == &mpam_resctrl_exports[RDT_RESOURCE_MC]) { - u64 range; + switch (ctrl_type) { + case SCHEMA_COMM: + if (res == &mpam_resctrl_exports[RDT_RESOURCE_MC]) { + u64 range; + + /* For MBA cfg is a percentage of .. */ + if (res->resctrl_mba_uses_mbw_part) { + /* .. the number of bits we can set */ + range = res->class->mbw_pbm_bits; + mpam_cfg->mbw_pbm = + (resctrl_cfg * range) / MAX_MBA_BW; + mpam_set_feature(mpam_feat_mbw_part, &mpam_cfg->valid); + } else { + /* .. the number of fractions we can represent */ + mpam_cfg->mbw_max = + bw_max_mask[(resctrl_cfg / 5 - 1) % + ARRAY_SIZE(bw_max_mask)];
- /* For MBA cfg is a percentage of .. */ - if (res->resctrl_mba_uses_mbw_part) { - /* .. the number of bits we can set */ - range = res->class->mbw_pbm_bits; - mpam_cfg->mbw_pbm = (resctrl_cfg * range) / MAX_MBA_BW; - mpam_set_feature(mpam_feat_mbw_part, &mpam_cfg->valid); + mpam_set_feature(mpam_feat_mbw_max, &mpam_cfg->valid); + } } else { - /* .. the number of fractions we can represent */ - mpam_cfg->mbw_max = bw_max_mask[(resctrl_cfg / 5 - 1) % - ARRAY_SIZE(bw_max_mask)]; - - mpam_set_feature(mpam_feat_mbw_max, &mpam_cfg->valid); + /* + * Nothing clever here as mpam_resctrl_pick_caches() + * capped the size at RESCTRL_MAX_CBM. + */ + mpam_cfg->cpbm = resctrl_cfg; + mpam_set_feature(mpam_feat_cpor_part, &mpam_cfg->valid); } - } else { - /* - * Nothing clever here as mpam_resctrl_pick_caches() - * capped the size at RESCTRL_MAX_CBM. - */ - mpam_cfg->cpbm = resctrl_cfg; - mpam_set_feature(mpam_feat_cpor_part, &mpam_cfg->valid); + break; + case SCHEMA_PRI: + mpam_cfg->dspri = resctrl_cfg; + mpam_cfg->intpri = resctrl_cfg; + mpam_set_feature(mpam_feat_dspri_part, &mpam_cfg->valid); + mpam_set_feature(mpam_feat_intpri_part, &mpam_cfg->valid); + break; + case SCHEMA_HDL: + mpam_cfg->hdl = resctrl_cfg; + mpam_set_feature(mpam_feat_part_hdl, &mpam_cfg->valid); + break; + default: + break; } }
+/* + * copy all ctrl type at once looks more efficient, as it + * only needs refresh devices' state once time through + * mpam_component_config, this feature will be checked + * again when appling configuration. + */ static void mpam_resctrl_update_component_cfg(struct resctrl_resource *r, - struct rdt_domain *d, struct list_head *opt_list, - struct sd_closid *closid) + struct rdt_domain *d, struct sd_closid *closid) { struct mpam_resctrl_dom *dom; struct mpam_resctrl_res *res; struct mpam_config *slave_mpam_cfg; + enum resctrl_ctrl_type type; u32 intpartid = closid->intpartid; u32 reqpartid = closid->reqpartid; - u32 resctrl_cfg = d->ctrl_val[intpartid]; + u32 resctrl_cfg;
lockdep_assert_held(&resctrl_group_mutex);
@@ -1481,9 +1631,18 @@ mpam_resctrl_update_component_cfg(struct resctrl_resource *r, slave_mpam_cfg = &dom->comp->cfg[reqpartid]; if (WARN_ON_ONCE(!slave_mpam_cfg)) return; - slave_mpam_cfg->valid = 0; - mpam_update_from_resctrl_cfg(res, resctrl_cfg, slave_mpam_cfg); + + for_each_ctrl_type(type) { + /* + * we don't need check if we have enabled this ctrl type, because + * this ctrls also should be applied an default configuration and + * this feature type would be rechecked when configuring mpam devices. + */ + resctrl_cfg = d->ctrl_val[type][intpartid]; + mpam_update_from_resctrl_cfg(res, resctrl_cfg, + type, slave_mpam_cfg); + } }
static void mpam_reset_cfg(struct mpam_resctrl_res *res, @@ -1492,11 +1651,14 @@ static void mpam_reset_cfg(struct mpam_resctrl_res *res, { int i; struct resctrl_resource *r = &res->resctrl_res; + enum resctrl_ctrl_type type;
for (i = 0; i != mpam_sysprops_num_partid(); i++) { - mpam_update_from_resctrl_cfg(res, r->default_ctrl, - &dom->comp->cfg[i]); - d->ctrl_val[i] = r->default_ctrl; + for_each_ctrl_type(type) { + mpam_update_from_resctrl_cfg(res, r->default_ctrl[type], + type, &dom->comp->cfg[i]); + d->ctrl_val[type][i] = r->default_ctrl[type]; + } } }
diff --git a/arch/arm64/kernel/mpam/mpam_setup.c b/arch/arm64/kernel/mpam/mpam_setup.c index b01716392a65..a06bd19be485 100644 --- a/arch/arm64/kernel/mpam/mpam_setup.c +++ b/arch/arm64/kernel/mpam/mpam_setup.c @@ -64,6 +64,7 @@ static int mpam_resctrl_setup_domain(unsigned int cpu, struct mpam_component *comp_iter, *comp; u32 num_partid; u32 **ctrlval_ptr; + enum resctrl_ctrl_type type;
num_partid = mpam_sysprops_num_partid();
@@ -88,12 +89,14 @@ static int mpam_resctrl_setup_domain(unsigned int cpu, dom->resctrl_dom.id = comp->comp_id; cpumask_set_cpu(cpu, &dom->resctrl_dom.cpu_mask);
- ctrlval_ptr = &dom->resctrl_dom.ctrl_val; - *ctrlval_ptr = kmalloc_array(num_partid, + for_each_ctrl_type(type) { + ctrlval_ptr = &dom->resctrl_dom.ctrl_val[type]; + *ctrlval_ptr = kmalloc_array(num_partid, sizeof(**ctrlval_ptr), GFP_KERNEL); - if (!*ctrlval_ptr) { - kfree(dom); - return -ENOMEM; + if (!*ctrlval_ptr) { + kfree(dom); + return -ENOMEM; + } }
/* TODO: this list should be sorted */ @@ -331,6 +334,13 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) struct resctrl_resource *r = &res->resctrl_res; struct raw_resctrl_resource *rr = NULL;
+ if (class && !r->default_ctrl) { + r->default_ctrl = kmalloc_array(SCHEMA_NUM_CTRL_TYPE, + sizeof(*r->default_ctrl), GFP_KERNEL); + if (!r->default_ctrl) + return -ENOMEM; + } + if (class == mpam_resctrl_exports[RDT_RESOURCE_SMMU].class) { return 0; } else if (class == mpam_resctrl_exports[RDT_RESOURCE_MC].class) { @@ -363,7 +373,7 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) r->mbw.min_bw = MAX_MBA_BW / ((1ULL << class->bwa_wd) - 1); /* the largest mbw_max is 100 */ - r->default_ctrl = 100; + r->default_ctrl[SCHEMA_COMM] = 100; } /* Just in case we have an excessive number of bits */ if (!r->mbw.min_bw) @@ -381,6 +391,9 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) rdt_alloc_capable = true; r->mon_capable = true; r->mon_enabled = true; + /* Export memory bandwidth hardlimit, default active hardlimit */ + rr->hdl_wd = 2; + r->default_ctrl[SCHEMA_HDL] = rr->hdl_wd - 1; } else if (class == mpam_resctrl_exports[RDT_RESOURCE_L3].class) { r->rid = RDT_RESOURCE_L3; rr = mpam_get_raw_resctrl_resource(RDT_RESOURCE_L3); @@ -390,14 +403,14 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) r->name = "L3";
r->cache.cbm_len = class->cpbm_wd; - r->default_ctrl = GENMASK(class->cpbm_wd - 1, 0); + r->default_ctrl[SCHEMA_COMM] = GENMASK(class->cpbm_wd - 1, 0); /* * Which bits are shared with other ...things... * Unknown devices use partid-0 which uses all the bitmap * fields. Until we configured the SMMU and GIC not to do this * 'all the bits' is the correct answer here. */ - r->cache.shareable_bits = r->default_ctrl; + r->cache.shareable_bits = r->default_ctrl[SCHEMA_COMM]; r->cache.min_cbm_bits = 1;
if (mpam_has_feature(mpam_feat_cpor_part, class->features)) { @@ -423,14 +436,14 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) r->name = "L2";
r->cache.cbm_len = class->cpbm_wd; - r->default_ctrl = GENMASK(class->cpbm_wd - 1, 0); + r->default_ctrl[SCHEMA_COMM] = GENMASK(class->cpbm_wd - 1, 0); /* * Which bits are shared with other ...things... * Unknown devices use partid-0 which uses all the bitmap * fields. Until we configured the SMMU and GIC not to do this * 'all the bits' is the correct answer here. */ - r->cache.shareable_bits = r->default_ctrl; + r->cache.shareable_bits = r->default_ctrl[SCHEMA_COMM];
if (mpam_has_feature(mpam_feat_cpor_part, class->features)) { r->alloc_capable = true; @@ -452,8 +465,10 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) rr->num_intpartid = class->num_intpartid; rr->num_pmg = class->num_pmg;
+ /* Export priority setting, default highest priority */ rr->pri_wd = max(class->intpri_wd, class->dspri_wd); - rr->hdl_wd = 2; + r->default_ctrl[SCHEMA_PRI] = (rr->pri_wd > 0) ? + rr->pri_wd - 1 : 0; }
return 0; diff --git a/include/linux/resctrlfs.h b/include/linux/resctrlfs.h index 684bcdba51de..7f1ff6e816f5 100644 --- a/include/linux/resctrlfs.h +++ b/include/linux/resctrlfs.h @@ -32,6 +32,8 @@ struct resctrl_cache { * @min_bw: Minimum memory bandwidth percentage user can request * @bw_gran: Granularity at which the memory bandwidth is allocated * @delay_linear: True if memory B/W delay is in linear scale + * @ctrl_extend_bits: Indicates if there are extra ctrl capabilities supported. + * e.g. priority/hardlimit. */ struct resctrl_membw { u32 min_bw; @@ -56,7 +58,9 @@ struct resctrl_resource {
bool cdp_capable; bool cdp_enable; - u32 default_ctrl; + u32 *default_ctrl; + + u32 ctrl_extend_bits;
void *res; };