diff --git a/arch/arm64/include/asm/mpam.h b/arch/arm64/include/asm/mpam.h index 5a76fb5d0fc6baec70664344a62906aae8244f23..6641180b4c3a18a14a2e1055693e1acdd2a3b4cd 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 cc863183e1beff300eec92b26b5e6512b70be34c..8868da13411bd8b9f2373a3b3a783f872b957266 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 8052a8bc08933e766398a07acd854ce0afd6ab97..e356dcbeb2462b290b8dd119afdd419b2eefc169 100644 --- a/arch/arm64/kernel/mpam/mpam_ctrlmon.c +++ b/arch/arm64/kernel/mpam/mpam_ctrlmon.c @@ -43,8 +43,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) @@ -73,7 +80,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) @@ -108,69 +158,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; } @@ -181,8 +250,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; @@ -203,11 +274,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; } } @@ -220,6 +293,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; @@ -228,10 +302,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); } } } @@ -316,7 +398,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; @@ -327,6 +410,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; @@ -335,13 +419,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 { @@ -362,6 +446,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) { @@ -378,7 +463,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 { @@ -604,12 +692,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]; + } } } @@ -626,7 +719,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; @@ -638,17 +732,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", @@ -656,8 +750,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 15896f69ca6da516c441b23b354617aad2cebdd5..3c056867aedfd1004b2fe3f928073dd3487f6f80 100644 --- a/arch/arm64/kernel/mpam/mpam_resctrl.c +++ b/arch/arm64/kernel/mpam/mpam_resctrl.c @@ -110,14 +110,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); @@ -127,16 +142,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, @@ -144,7 +159,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, @@ -169,33 +184,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; @@ -204,10 +199,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; @@ -258,7 +267,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; @@ -267,10 +277,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; @@ -278,14 +302,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, @@ -302,31 +326,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; } /* @@ -649,6 +717,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; @@ -656,6 +770,7 @@ int parse_rdtgroupfs_options(char *data) int ret = 0; disable_cdp(); + extend_ctrl_disable(); while ((token = strsep(&o, ",")) != NULL) { if (!*token) { @@ -671,12 +786,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: @@ -1427,45 +1552,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); @@ -1486,9 +1636,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, @@ -1497,11 +1656,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 b01716392a6570e581dbc4560e72c53431f2bdc8..a06bd19be4853b2e9cea5d4a1fe144f7692c1b38 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 684bcdba51de6618c5fcc8657b2e2e786cdbfee1..7f1ff6e816f5179f49c4f974ce1a44711d93c991 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; };