[PATCH OLK-6.6 0/5] arm64/mpam: Extending MPAM's QoS capability

Zeng Heng (5): fs/resctrl: As a pre-patch for extending MPAM's QoS capability arm64/mpam: Add CMAX feature arm64/mpam: Add mbw_min and cmin features arm64/mpam: Add PRIO feature arm64/mpam: Add limit feature arch/x86/kernel/cpu/resctrl/core.c | 6 +- drivers/platform/mpam/mpam_devices.c | 85 +++++-- drivers/platform/mpam/mpam_internal.h | 16 +- drivers/platform/mpam/mpam_resctrl.c | 326 +++++++++++++++++++++++--- fs/resctrl/ctrlmondata.c | 13 +- fs/resctrl/rdtgroup.c | 13 +- include/linux/resctrl.h | 19 +- include/linux/resctrl_types.h | 9 + 8 files changed, 417 insertions(+), 70 deletions(-) -- 2.25.1

反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/16035 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/BPP... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/16035 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/BPP...

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC35SV -------------------------------- In the following patches, we would introduce many QoS configuration in order to enhance MPAM's capability for isolating interference and schedule shared resources. As a prerequisite patch, it introduces the resctrl_schema_fmt, an enumeration type that indicates the format in which resource configurations are issued by users. Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- arch/x86/kernel/cpu/resctrl/core.c | 6 ++- drivers/platform/mpam/mpam_resctrl.c | 70 ++++++++++++++++------------ fs/resctrl/ctrlmondata.c | 13 ++++-- fs/resctrl/rdtgroup.c | 13 ++++-- include/linux/resctrl.h | 13 +++++- 5 files changed, 75 insertions(+), 40 deletions(-) diff --git a/arch/x86/kernel/cpu/resctrl/core.c b/arch/x86/kernel/cpu/resctrl/core.c index 6a5a5b43af27..77210107653a 100644 --- a/arch/x86/kernel/cpu/resctrl/core.c +++ b/arch/x86/kernel/cpu/resctrl/core.c @@ -61,7 +61,7 @@ mba_wrmsr_amd(struct rdt_domain *d, struct msr_param *m, #define domain_init(id) LIST_HEAD_INIT(rdt_resources_all[id].r_resctrl.domains) -struct rdt_hw_resource rdt_resources_all[] = { +struct rdt_hw_resource rdt_resources_all[RDT_NUM_RESOURCES] = { [RDT_RESOURCE_L3] = { .r_resctrl = { @@ -71,6 +71,7 @@ struct rdt_hw_resource rdt_resources_all[] = { .domains = domain_init(RDT_RESOURCE_L3), .format_str = "%d=%0*x", .fflags = RFTYPE_RES_CACHE, + .schema_fmt = RESCTRL_SCHEMA_BITMAP, }, .msr_base = MSR_IA32_L3_CBM_BASE, .msr_update = cat_wrmsr, @@ -84,6 +85,7 @@ struct rdt_hw_resource rdt_resources_all[] = { .domains = domain_init(RDT_RESOURCE_L2), .format_str = "%d=%0*x", .fflags = RFTYPE_RES_CACHE, + .schema_fmt = RESCTRL_SCHEMA_BITMAP, }, .msr_base = MSR_IA32_L2_CBM_BASE, .msr_update = cat_wrmsr, @@ -97,6 +99,7 @@ struct rdt_hw_resource rdt_resources_all[] = { .domains = domain_init(RDT_RESOURCE_MBA), .format_str = "%d=%*u", .fflags = RFTYPE_RES_MB, + .schema_fmt = RESCTRL_SCHEMA_PERCENT, }, }, [RDT_RESOURCE_SMBA] = @@ -108,6 +111,7 @@ struct rdt_hw_resource rdt_resources_all[] = { .domains = domain_init(RDT_RESOURCE_SMBA), .format_str = "%d=%*u", .fflags = RFTYPE_RES_MB, + .schema_fmt = RESCTRL_SCHEMA_PERCENT, }, }, }; diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 7586c8ffbb88..5080271fdcaa 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -581,6 +581,9 @@ static u32 mbw_max_to_percent(u16 mbw_max, u8 wd) u8 bit; u32 divisor = 2, value = 0, precision = get_wd_precision(wd); + if (mbw_max == GENMASK(15, 15 - wd + 1)) + return MAX_MBA_BW; + for (bit = 15; bit; bit--) { if (mbw_max & BIT(bit)) value += MAX_MBA_BW * precision / divisor; @@ -610,6 +613,9 @@ static u16 percent_to_mbw_max(u32 pc, u8 wd) if (WARN_ON_ONCE(wd > 15)) return MAX_MBA_BW; + if (pc == MAX_MBA_BW) + return GENMASK(15, 15 - wd + 1); + pc *= precision; for (bit = 15; bit; bit--) { @@ -677,22 +683,25 @@ static void mpam_resctrl_pick_caches(void) if (mpam_has_feature(mpam_feat_msmon_csu, cprops)) update_rmid_limits(cache_size); - if (class->level == 2) { - res = &mpam_resctrl_exports[RDT_RESOURCE_L2]; - res->resctrl_res.name = "L2"; - } else { - res = &mpam_resctrl_exports[RDT_RESOURCE_L3]; - res->resctrl_res.name = "L3"; + if (has_cpor) { + if (class->level == 2) { + res = &mpam_resctrl_exports[RDT_RESOURCE_L2]; + res->resctrl_res.name = "L2"; + } else { + res = &mpam_resctrl_exports[RDT_RESOURCE_L3]; + res->resctrl_res.name = "L3"; + } + res->class = class; } - res->class = class; } srcu_read_unlock(&mpam_srcu, idx); } static void mpam_resctrl_pick_mba(void) { - struct mpam_class *class, *candidate_class = NULL; struct mpam_resctrl_res *res; + struct mpam_class *class; + bool has_mba; int idx; lockdep_assert_cpus_held(); @@ -701,6 +710,8 @@ static void mpam_resctrl_pick_mba(void) list_for_each_entry_rcu(class, &mpam_classes, classes_list) { struct mpam_props *cprops = &class->props; + has_mba = class_has_usable_mba(cprops); + if (class->level < 3) continue; @@ -710,21 +721,13 @@ static void mpam_resctrl_pick_mba(void) if (!cpumask_equal(&class->affinity, cpu_possible_mask)) continue; - /* - * mba_sc reads the mbm_local counter, and waggles the MBA controls. - * mbm_local is implicitly part of the L3, pick a resouce to be MBA - * that as close as possible to the L3. - */ - if (!candidate_class || class->level < candidate_class->level) - candidate_class = class; + if (has_mba) { + res = &mpam_resctrl_exports[RDT_RESOURCE_MBA]; + res->class = class; + res->resctrl_res.name = "MB"; + } } srcu_read_unlock(&mpam_srcu, idx); - - if (candidate_class) { - res = &mpam_resctrl_exports[RDT_RESOURCE_MBA]; - res->class = candidate_class; - res->resctrl_res.name = "MB"; - } } bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt) @@ -778,14 +781,15 @@ void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_domain *d) static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) { struct mpam_class *class = res->class; + struct mpam_props *cprops = &class->props; struct rdt_resource *r = &res->resctrl_res; bool has_mbwu = class_has_usable_mbwu(class); + bool has_csu = cache_has_usable_csu(class); /* Is this one of the two well-known caches? */ - if (res->resctrl_res.rid == RDT_RESOURCE_L2 || - res->resctrl_res.rid == RDT_RESOURCE_L3) { - bool has_csu = cache_has_usable_csu(class); - + switch (res->resctrl_res.rid) { + case RDT_RESOURCE_L2: + case RDT_RESOURCE_L3: /* TODO: Scaling is not yet supported */ r->cache.cbm_len = class->props.cpbm_wd; r->cache.arch_has_sparse_bitmasks = true; @@ -795,6 +799,7 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) /* TODO: kill these properties off as they are derivatives */ r->format_str = "%d=%0*x"; + r->schema_fmt = RESCTRL_SCHEMA_BITMAP; r->fflags = RFTYPE_RES_CACHE; r->default_ctrl = BIT_MASK(class->props.cpbm_wd) - 1; r->data_width = (class->props.cpbm_wd + 3) / 4; @@ -808,7 +813,7 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) */ r->cache.shareable_bits = r->default_ctrl; - if (mpam_has_feature(mpam_feat_cpor_part, &class->props)) { + if (mpam_has_feature(mpam_feat_cpor_part, cprops)) { r->alloc_capable = true; exposed_alloc_capable = true; } @@ -832,11 +837,12 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) class->level == 3) { r->mon_capable = true; } - } else if (res->resctrl_res.rid == RDT_RESOURCE_MBA) { - struct mpam_props *cprops = &class->props; + break; + case RDT_RESOURCE_MBA: /* TODO: kill these properties off as they are derivatives */ r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; r->fflags = RFTYPE_RES_MB; r->default_ctrl = MAX_MBA_BW; r->data_width = 3; @@ -858,6 +864,10 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) mbm_total_class = class; r->mon_capable = true; } + break; + + default: + break; } if (r->mon_capable) { @@ -871,7 +881,7 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) * For mpam, each control group has its own pmg/rmid * space. */ - r->num_rmid = 1; + r->num_rmid = mpam_partid_max * mpam_pmg_max; } return 0; @@ -1027,6 +1037,8 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, if (!r->alloc_capable || partid >= resctrl_arch_get_num_closid(r)) return -EINVAL; + cfg = dom->comp->cfg[partid]; + switch (r->rid) { case RDT_RESOURCE_L2: case RDT_RESOURCE_L3: diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c index 15df4334ff14..60b422eed2c8 100644 --- a/fs/resctrl/ctrlmondata.c +++ b/fs/resctrl/ctrlmondata.c @@ -45,20 +45,23 @@ static bool bw_validate(char *buf, unsigned long *data, struct rdt_resource *r) * Only linear delay values is supported for current Intel SKUs. */ if (!r->membw.delay_linear && r->membw.arch_needs_linear) { - rdt_last_cmd_puts("No support for non-linear MB domains\n"); + rdt_last_cmd_printf("No support for non-linear %s domains\n", + r->name); return false; } ret = kstrtoul(buf, 10, &bw); if (ret) { - rdt_last_cmd_printf("Non-decimal digit in MB value %s\n", buf); + rdt_last_cmd_printf("Non-decimal digit in %s value %s\n", + r->name, buf); return false; } if ((bw < r->membw.min_bw || bw > r->default_ctrl) && !is_mba_sc(r)) { - rdt_last_cmd_printf("MB value %ld out of range [%d,%d]\n", bw, - r->membw.min_bw, r->default_ctrl); + rdt_last_cmd_printf("%s value %ld out of range [%d,%d]\n", + r->name, bw, r->membw.min_bw, + r->default_ctrl); return false; } @@ -227,7 +230,7 @@ static int parse_cbm(struct rdt_parse_data *data, struct resctrl_schema *s, static ctrlval_parser_t *get_parser(struct rdt_resource *res) { - if (res->fflags & RFTYPE_RES_CACHE) + if (res->schema_fmt == RESCTRL_SCHEMA_BITMAP) return &parse_cbm; else return &parse_bw; diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c index 4b38a68cc0f3..ffb6b8930435 100644 --- a/fs/resctrl/rdtgroup.c +++ b/fs/resctrl/rdtgroup.c @@ -1679,11 +1679,11 @@ static int rdtgroup_size_show(struct kernfs_open_file *of, ctrl = resctrl_arch_get_config(r, d, closid, type); - if (r->rid == RDT_RESOURCE_MBA || - r->rid == RDT_RESOURCE_SMBA) - size = ctrl; - else + if (r->rid == RDT_RESOURCE_L3 || + r->rid == RDT_RESOURCE_L2) size = rdtgroup_cbm_to_size(r, d, ctrl); + else + size = ctrl; } seq_printf(s, "%d=%u", d->id, size); sep = true; @@ -2293,6 +2293,11 @@ static int rdtgroup_create_info_dir(struct kernfs_node *parent_kn) /* loop over enabled controls, these are all alloc_capable */ list_for_each_entry(s, &resctrl_schema_all, list) { r = s->res; + + /* Not supported yet */ + if (r->rid > RDT_RESOURCE_SMBA) + continue; + fflags = r->fflags | RFTYPE_CTRL_INFO; ret = rdtgroup_mkdir_info_resdir(s, s->name, fflags); if (ret) diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 61ff7dd5d74c..4b0f57ddeb0e 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -177,6 +177,16 @@ struct resctrl_membw { u32 *mb_map; }; +/** + * enum resctrl_schema_fmt - The format user-space provides for a schema. + * @RESCTRL_SCHEMA_BITMAP: The schema is a bitmap in hex. + * @RESCTRL_SCHEMA_PERCENT: The schema is a percentage. + */ +enum resctrl_schema_fmt { + RESCTRL_SCHEMA_BITMAP, + RESCTRL_SCHEMA_PERCENT, +}; + /** * struct rdt_resource - attributes of a resctrl resource * @rid: The index of the resource @@ -211,6 +221,7 @@ struct rdt_resource { struct list_head evt_list; unsigned long fflags; bool cdp_capable; + enum resctrl_schema_fmt schema_fmt; }; /* @@ -234,7 +245,7 @@ struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l); */ struct resctrl_schema { struct list_head list; - char name[8]; + char name[16]; enum resctrl_conf_type conf_type; struct rdt_resource *res; u32 num_closid; -- 2.25.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC35SV -------------------------------- Implement the cmax interface and allow users can configure the cache maximum capacity by the schemata interface under the resctrl fs. User can update CMAX settings by the interface {L2,L3}MAX:${domain_id}=${value} in the schemata file. When the cache occupancy of the target PARTID does not reach the cmax configuration, allows to use the shared resources with higher priority. Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 10 ++++-- drivers/platform/mpam/mpam_internal.h | 3 +- drivers/platform/mpam/mpam_resctrl.c | 51 ++++++++++++++++++++++++++- include/linux/resctrl_types.h | 2 ++ 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index 698b3dec3fa5..9e9584bb6a17 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -1215,6 +1215,13 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, rprops->cpbm_wd); } + if (mpam_has_feature(mpam_feat_ccap_part, rprops)) { + if (mpam_has_feature(mpam_feat_ccap_part, cfg)) + mpam_write_partsel_reg(msc, CMAX, cfg->cmax); + else + mpam_write_partsel_reg(msc, CMAX, cmax); + } + if (mpam_has_feature(mpam_feat_mbw_part, rprops)) { if (mpam_has_feature(mpam_feat_mbw_part, cfg)) mpam_write_partsel_reg(msc, MBW_PBM, cfg->mbw_pbm); @@ -1236,9 +1243,6 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, if (mpam_has_feature(mpam_feat_mbw_prop, rprops)) mpam_write_partsel_reg(msc, MBW_PROP, bwa_fract); - if (mpam_has_feature(mpam_feat_ccap_part, rprops)) - mpam_write_partsel_reg(msc, CMAX, cmax); - if (mpam_has_feature(mpam_feat_intpri_part, rprops) || mpam_has_feature(mpam_feat_dspri_part, rprops)) { /* aces high? */ diff --git a/drivers/platform/mpam/mpam_internal.h b/drivers/platform/mpam/mpam_internal.h index d8854cc6f78e..c650eb878cd2 100644 --- a/drivers/platform/mpam/mpam_internal.h +++ b/drivers/platform/mpam/mpam_internal.h @@ -52,7 +52,7 @@ struct mpam_msc struct mpam_msc * __percpu *error_dev_id; atomic_t online_refs; - + struct mutex lock; bool probed; bool error_irq_requested; @@ -162,6 +162,7 @@ struct mpam_config { u32 cpbm; u32 mbw_pbm; u16 mbw_max; + u16 cmax; }; struct mpam_component diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 5080271fdcaa..6ea90d0009ea 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -483,6 +483,13 @@ static bool cache_has_usable_cpor(struct mpam_class *class) return (class->props.cpbm_wd <= RESCTRL_MAX_CBM); } +static bool cache_has_usable_cmax(struct mpam_class *class) +{ + struct mpam_props *cprops = &class->props; + + return mpam_has_feature(mpam_feat_ccap_part, cprops); +} + static bool cache_has_usable_csu(struct mpam_class *class) { struct mpam_props *cprops; @@ -639,6 +646,7 @@ static void mpam_resctrl_pick_caches(void) { int idx; unsigned int cache_size; + bool has_cpor, has_cmax; struct mpam_class *class; struct mpam_resctrl_res *res; @@ -647,7 +655,9 @@ static void mpam_resctrl_pick_caches(void) idx = srcu_read_lock(&mpam_srcu); list_for_each_entry_rcu(class, &mpam_classes, classes_list) { struct mpam_props *cprops = &class->props; - bool has_cpor = cache_has_usable_cpor(class); + + has_cpor = cache_has_usable_cpor(class); + has_cmax = cache_has_usable_cmax(class); if (class->type != MPAM_CLASS_CACHE) { pr_debug("pick_caches: Class is not a cache\n"); @@ -693,6 +703,17 @@ static void mpam_resctrl_pick_caches(void) } res->class = class; } + + if (has_cmax) { + if (class->level == 2) { + res = &mpam_resctrl_exports[RDT_RESOURCE_L2_MAX]; + res->resctrl_res.name = "L2MAX"; + } else { + res = &mpam_resctrl_exports[RDT_RESOURCE_L3_MAX]; + res->resctrl_res.name = "L3MAX"; + } + res->class = class; + } } srcu_read_unlock(&mpam_srcu, idx); } @@ -866,6 +887,22 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) } break; + case RDT_RESOURCE_L3_MAX: + case RDT_RESOURCE_L2_MAX: + r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; + r->fflags = RFTYPE_RES_CACHE; + r->default_ctrl = MAX_MBA_BW; + r->data_width = 3; + r->cache_level = class->level; + + if (cache_has_usable_cmax(class)) + r->alloc_capable = true; + + r->membw.min_bw = 0; + r->membw.bw_gran = max(100 / (1 << cprops->cmax_wd), 1); + break; + default: break; } @@ -984,6 +1021,11 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, case RDT_RESOURCE_L3: configured_by = mpam_feat_cpor_part; break; + case RDT_RESOURCE_L2_MAX: + case RDT_RESOURCE_L3_MAX: + configured_by = mpam_feat_ccap_part; + break; + case RDT_RESOURCE_MBA: if (mba_class_use_mbw_part(cprops)) { configured_by = mpam_feat_mbw_part; @@ -1005,6 +1047,8 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, case mpam_feat_cpor_part: /* TODO: Scaling is not yet supported */ return cfg->cpbm; + case mpam_feat_ccap_part: + return mbw_max_to_percent(cfg->cmax, cprops->cmax_wd); case mpam_feat_mbw_part: /* TODO: Scaling is not yet supported */ return mbw_pbm_to_percent(cfg->mbw_pbm, cprops); @@ -1046,6 +1090,11 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, cfg.cpbm = cfg_val; mpam_set_feature(mpam_feat_cpor_part, &cfg); break; + case RDT_RESOURCE_L2_MAX: + case RDT_RESOURCE_L3_MAX: + cfg.cmax = percent_to_mbw_max(cfg_val, cprops->cmax_wd); + mpam_set_feature(mpam_feat_ccap_part, &cfg); + break; case RDT_RESOURCE_MBA: if (mba_class_use_mbw_part(cprops)) { cfg.mbw_pbm = percent_to_mbw_pbm(cfg_val, cprops); diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h index 44f7a47f986b..a2bc881b2d75 100644 --- a/include/linux/resctrl_types.h +++ b/include/linux/resctrl_types.h @@ -78,6 +78,8 @@ enum resctrl_res_level { RDT_RESOURCE_L2, RDT_RESOURCE_MBA, RDT_RESOURCE_SMBA, + RDT_RESOURCE_L3_MAX, + RDT_RESOURCE_L2_MAX, /* Must be the last */ RDT_NUM_RESOURCES, -- 2.25.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC35SV -------------------------------- Implement mbw_min/cmin feature for mata/cache msc, and provide MBMIN/LxMIN interface in schemata file for user. On some specific platforms, L3 implements the cmin feature, but L2 may not provide it, or vice versa. Therefore, it is necessary to separately determine whether the cache msc has implemented the corresponding feature. Before transmitting the cache MIN portion value to msc, need to check whether the CMIN setting from user space is validate or not. The same goes for MBMIN. It should be noted that the new configuration value is in decimal form instead of hexadecimal, so here reuse the parse_bw() to analysis input value for cache msc. Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 26 +++++-- drivers/platform/mpam/mpam_internal.h | 4 + drivers/platform/mpam/mpam_resctrl.c | 102 ++++++++++++++++++++++++-- include/linux/resctrl_types.h | 3 + 4 files changed, 123 insertions(+), 12 deletions(-) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index 9e9584bb6a17..81645f19180b 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -581,9 +581,14 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) u32 ccap_features = mpam_read_partsel_reg(msc, CCAP_IDR); props->cmax_wd = FIELD_GET(MPAMF_CCAP_IDR_CMAX_WD, ccap_features); - if (props->cmax_wd && - !FIELD_GET(MPAMF_CCAP_IDR_NO_CMAX, ccap_features)) - mpam_set_feature(mpam_feat_ccap_part, props); + + if (props->cmax_wd) { + if (!FIELD_GET(MPAMF_CCAP_IDR_NO_CMAX, ccap_features)) + mpam_set_feature(mpam_feat_ccap_part, props); + + if (FIELD_GET(MPAMF_CCAP_IDR_HAS_CMIN, ccap_features)) + mpam_set_feature(mpam_feat_cmin, props); + } } /* Cache Portion partitioning */ @@ -1222,6 +1227,13 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, mpam_write_partsel_reg(msc, CMAX, cmax); } + if (mpam_has_feature(mpam_feat_cmin, rprops)) { + if (mpam_has_feature(mpam_feat_cmin, cfg)) + mpam_write_partsel_reg(msc, CMIN, cfg->cmin); + else + mpam_write_partsel_reg(msc, CMIN, 0); + } + if (mpam_has_feature(mpam_feat_mbw_part, rprops)) { if (mpam_has_feature(mpam_feat_mbw_part, cfg)) mpam_write_partsel_reg(msc, MBW_PBM, cfg->mbw_pbm); @@ -1230,8 +1242,12 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, rprops->mbw_pbm_bits); } - if (mpam_has_feature(mpam_feat_mbw_min, rprops)) - mpam_write_partsel_reg(msc, MBW_MIN, 0); + if (mpam_has_feature(mpam_feat_mbw_min, rprops)) { + if (mpam_has_feature(mpam_feat_mbw_min, cfg)) + mpam_write_partsel_reg(msc, MBW_MIN, cfg->mbw_min); + else + mpam_write_partsel_reg(msc, MBW_MIN, 0); + } if (mpam_has_feature(mpam_feat_mbw_max, rprops)) { if (mpam_has_feature(mpam_feat_mbw_max, cfg)) diff --git a/drivers/platform/mpam/mpam_internal.h b/drivers/platform/mpam/mpam_internal.h index c650eb878cd2..6555c2def51a 100644 --- a/drivers/platform/mpam/mpam_internal.h +++ b/drivers/platform/mpam/mpam_internal.h @@ -86,6 +86,7 @@ typedef u32 mpam_features_t; enum mpam_device_features { mpam_feat_ccap_part = 0, mpam_feat_cpor_part, + mpam_feat_cmin, mpam_feat_mbw_part, mpam_feat_mbw_min, mpam_feat_mbw_max, @@ -162,7 +163,9 @@ struct mpam_config { u32 cpbm; u32 mbw_pbm; u16 mbw_max; + u16 mbw_min; u16 cmax; + u16 cmin; }; struct mpam_component @@ -342,6 +345,7 @@ void mpam_resctrl_exit(void); #define MPAMCFG_PART_SEL 0x0100 /* partid to configure: */ #define MPAMCFG_CPBM 0x1000 /* cache-portion config */ #define MPAMCFG_CMAX 0x0108 /* cache-capacity config */ +#define MPAMCFG_CMIN 0x0110 /* cache-capacity min config */ #define MPAMCFG_MBW_MIN 0x0200 /* min mem-bw config */ #define MPAMCFG_MBW_MAX 0x0208 /* max mem-bw config */ #define MPAMCFG_MBW_WINWD 0x0220 /* mem-bw accounting window config */ diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 6ea90d0009ea..4ecff61ddcd9 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -490,6 +490,13 @@ static bool cache_has_usable_cmax(struct mpam_class *class) return mpam_has_feature(mpam_feat_ccap_part, cprops); } +static bool cache_has_usable_cmin(struct mpam_class *class) +{ + struct mpam_props *cprops = &class->props; + + return mpam_has_feature(mpam_feat_cmin, cprops); +} + static bool cache_has_usable_csu(struct mpam_class *class) { struct mpam_props *cprops; @@ -543,6 +550,14 @@ static bool class_has_usable_mba(struct mpam_props *cprops) return false; } +static bool class_has_usable_mbw_min(struct mpam_props *cprops) +{ + if (mpam_has_feature(mpam_feat_mbw_min, cprops)) + return true; + + return false; +} + /* * Calculate the percentage change from each implemented bit in the control * This can return 0 when BWA_WD is greater than 6. (100 / (1<<7) == 0) @@ -646,9 +661,9 @@ static void mpam_resctrl_pick_caches(void) { int idx; unsigned int cache_size; - bool has_cpor, has_cmax; struct mpam_class *class; struct mpam_resctrl_res *res; + bool has_cpor, has_cmax, has_cmin; lockdep_assert_cpus_held(); @@ -658,6 +673,7 @@ static void mpam_resctrl_pick_caches(void) has_cpor = cache_has_usable_cpor(class); has_cmax = cache_has_usable_cmax(class); + has_cmin = cache_has_usable_cmin(class); if (class->type != MPAM_CLASS_CACHE) { pr_debug("pick_caches: Class is not a cache\n"); @@ -714,6 +730,17 @@ static void mpam_resctrl_pick_caches(void) } res->class = class; } + + if (has_cmin) { + if (class->level == 2) { + res = &mpam_resctrl_exports[RDT_RESOURCE_L2_MIN]; + res->resctrl_res.name = "L2MIN"; + } else { + res = &mpam_resctrl_exports[RDT_RESOURCE_L3_MIN]; + res->resctrl_res.name = "L3MIN"; + } + res->class = class; + } } srcu_read_unlock(&mpam_srcu, idx); } @@ -721,8 +748,8 @@ static void mpam_resctrl_pick_caches(void) static void mpam_resctrl_pick_mba(void) { struct mpam_resctrl_res *res; + bool has_mba, has_mbw_min; struct mpam_class *class; - bool has_mba; int idx; lockdep_assert_cpus_held(); @@ -732,13 +759,11 @@ static void mpam_resctrl_pick_mba(void) struct mpam_props *cprops = &class->props; has_mba = class_has_usable_mba(cprops); + has_mbw_min = class_has_usable_mbw_min(cprops); if (class->level < 3) continue; - if (!class_has_usable_mba(cprops)) - continue; - if (!cpumask_equal(&class->affinity, cpu_possible_mask)) continue; @@ -747,6 +772,12 @@ static void mpam_resctrl_pick_mba(void) res->class = class; res->resctrl_res.name = "MB"; } + + if (has_mbw_min) { + res = &mpam_resctrl_exports[RDT_RESOURCE_MB_MIN]; + res->class = class; + res->resctrl_res.name = "MBMIN"; + } } srcu_read_unlock(&mpam_srcu, idx); } @@ -903,6 +934,41 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) r->membw.bw_gran = max(100 / (1 << cprops->cmax_wd), 1); break; + case RDT_RESOURCE_L3_MIN: + case RDT_RESOURCE_L2_MIN: + r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; + r->fflags = RFTYPE_RES_CACHE; + r->default_ctrl = MAX_MBA_BW; + r->data_width = 3; + r->cache_level = class->level; + + if (cache_has_usable_cmin(class)) + r->alloc_capable = true; + + r->membw.min_bw = 0; + r->membw.bw_gran = max(100 / (1 << cprops->cmax_wd), 1); + break; + + case RDT_RESOURCE_MB_MIN: + r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; + r->fflags = RFTYPE_RES_MB; + r->default_ctrl = MAX_MBA_BW; + r->data_width = 3; + + r->membw.delay_linear = true; + r->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED; + r->membw.bw_gran = get_mba_granularity(cprops); + + /* Round up to at least 1% */ + if (!r->membw.bw_gran) + r->membw.bw_gran = 1; + + if (class_has_usable_mbw_min(cprops)) + r->alloc_capable = true; + break; + default: break; } @@ -1025,6 +1091,10 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, case RDT_RESOURCE_L3_MAX: configured_by = mpam_feat_ccap_part; break; + case RDT_RESOURCE_L2_MIN: + case RDT_RESOURCE_L3_MIN: + configured_by = mpam_feat_cmin; + break; case RDT_RESOURCE_MBA: if (mba_class_use_mbw_part(cprops)) { @@ -1034,7 +1104,12 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, configured_by = mpam_feat_mbw_max; break; } - fallthrough; + return -EINVAL; + + case RDT_RESOURCE_MB_MIN: + configured_by = mpam_feat_mbw_min; + break; + default: return -EINVAL; } @@ -1049,11 +1124,15 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, return cfg->cpbm; case mpam_feat_ccap_part: return mbw_max_to_percent(cfg->cmax, cprops->cmax_wd); + case mpam_feat_cmin: + return mbw_max_to_percent(cfg->cmin, cprops->cmax_wd); case mpam_feat_mbw_part: /* TODO: Scaling is not yet supported */ return mbw_pbm_to_percent(cfg->mbw_pbm, cprops); case mpam_feat_mbw_max: return mbw_max_to_percent(cfg->mbw_max, cprops->bwa_wd); + case mpam_feat_mbw_min: + return mbw_max_to_percent(cfg->mbw_min, cprops->bwa_wd); default: return -EINVAL; } @@ -1095,6 +1174,11 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, cfg.cmax = percent_to_mbw_max(cfg_val, cprops->cmax_wd); mpam_set_feature(mpam_feat_ccap_part, &cfg); break; + case RDT_RESOURCE_L2_MIN: + case RDT_RESOURCE_L3_MIN: + cfg.cmin = percent_to_mbw_max(cfg_val, cprops->cmax_wd); + mpam_set_feature(mpam_feat_cmin, &cfg); + break; case RDT_RESOURCE_MBA: if (mba_class_use_mbw_part(cprops)) { cfg.mbw_pbm = percent_to_mbw_pbm(cfg_val, cprops); @@ -1105,7 +1189,11 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, mpam_set_feature(mpam_feat_mbw_max, &cfg); break; } - fallthrough; + return -EINVAL; + case RDT_RESOURCE_MB_MIN: + cfg.mbw_min = percent_to_mbw_max(cfg_val, cprops->bwa_wd); + mpam_set_feature(mpam_feat_mbw_min, &cfg); + break; default: return -EINVAL; } diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h index a2bc881b2d75..a5c36ffaa0c2 100644 --- a/include/linux/resctrl_types.h +++ b/include/linux/resctrl_types.h @@ -80,6 +80,9 @@ enum resctrl_res_level { RDT_RESOURCE_SMBA, RDT_RESOURCE_L3_MAX, RDT_RESOURCE_L2_MAX, + RDT_RESOURCE_L3_MIN, + RDT_RESOURCE_L2_MIN, + RDT_RESOURCE_MB_MIN, /* Must be the last */ RDT_NUM_RESOURCES, -- 2.25.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC35SV -------------------------------- The Priority Partition feature controls the priority of requests attributed to the target PARTID. In addition to the MATA msc implementing priority features, the L3 controller can also have the same features. Here the *MBPRI* and *L3PRI* interface are provided in the schemata file to allow users to configure and query QoS partition settings. Before transmitting the priority value to msc, it needs to check whether the setting from user is validate or not. Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 35 ++++++++----- drivers/platform/mpam/mpam_internal.h | 7 +++ drivers/platform/mpam/mpam_resctrl.c | 73 ++++++++++++++++++++++++++- include/linux/resctrl.h | 6 +++ include/linux/resctrl_types.h | 3 ++ 5 files changed, 108 insertions(+), 16 deletions(-) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index 81645f19180b..0614ae4d382a 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -1198,12 +1198,11 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, struct mpam_config *cfg) { u32 pri_val = 0; + u16 intpri, dspri; u16 cmax = MPAMCFG_CMAX_CMAX; struct mpam_msc *msc = ris->msc; u16 bwa_fract = MPAMCFG_MBW_MAX_MAX; struct mpam_props *rprops = &ris->props; - u16 dspri = GENMASK(rprops->dspri_wd, 0); - u16 intpri = GENMASK(rprops->intpri_wd, 0); spin_lock(&msc->part_sel_lock); __mpam_part_sel(ris->ris_idx, partid, msc); @@ -1259,21 +1258,29 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, if (mpam_has_feature(mpam_feat_mbw_prop, rprops)) mpam_write_partsel_reg(msc, MBW_PROP, bwa_fract); - if (mpam_has_feature(mpam_feat_intpri_part, rprops) || - mpam_has_feature(mpam_feat_dspri_part, rprops)) { - /* aces high? */ - if (!mpam_has_feature(mpam_feat_intpri_part_0_low, rprops)) - intpri = 0; - if (!mpam_has_feature(mpam_feat_dspri_part_0_low, rprops)) - dspri = 0; - - if (mpam_has_feature(mpam_feat_intpri_part, rprops)) + if (mpam_has_feature(mpam_feat_intpri_part_0_low, rprops)) + intpri = GENMASK(rprops->intpri_wd - 1, 0); + else + intpri = 0; + + if (mpam_has_feature(mpam_feat_intpri_part, rprops)) { + if (mpam_has_feature(mpam_feat_intpri_part, cfg)) + pri_val |= FIELD_PREP(MPAMCFG_PRI_INTPRI, cfg->intpri); + else pri_val |= FIELD_PREP(MPAMCFG_PRI_INTPRI, intpri); - if (mpam_has_feature(mpam_feat_dspri_part, rprops)) - pri_val |= FIELD_PREP(MPAMCFG_PRI_DSPRI, dspri); + } + if (mpam_has_feature(mpam_feat_dspri_part_0_low, rprops)) + dspri = GENMASK(rprops->dspri_wd - 1, 0); + else + dspri = 0; + + if (mpam_has_feature(mpam_feat_dspri_part, rprops)) + pri_val |= FIELD_PREP(MPAMCFG_PRI_DSPRI, dspri); + + if (mpam_has_feature(mpam_feat_intpri_part, rprops) || + mpam_has_feature(mpam_feat_dspri_part, rprops)) mpam_write_partsel_reg(msc, PRI, pri_val); - } spin_unlock(&msc->part_sel_lock); } diff --git a/drivers/platform/mpam/mpam_internal.h b/drivers/platform/mpam/mpam_internal.h index 6555c2def51a..47582ddc554f 100644 --- a/drivers/platform/mpam/mpam_internal.h +++ b/drivers/platform/mpam/mpam_internal.h @@ -166,6 +166,13 @@ struct mpam_config { u16 mbw_min; u16 cmax; u16 cmin; + + /* + * dspri is downstream priority + * intpri is internal priority + */ + u16 dspri; + u16 intpri; }; struct mpam_component diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 4ecff61ddcd9..b4e004281745 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -558,6 +558,14 @@ static bool class_has_usable_mbw_min(struct mpam_props *cprops) return false; } +static bool class_has_usable_intpri(struct mpam_props *cprops) +{ + if (mpam_has_feature(mpam_feat_intpri_part, cprops)) + return true; + + return false; +} + /* * Calculate the percentage change from each implemented bit in the control * This can return 0 when BWA_WD is greater than 6. (100 / (1<<7) == 0) @@ -663,7 +671,7 @@ static void mpam_resctrl_pick_caches(void) unsigned int cache_size; struct mpam_class *class; struct mpam_resctrl_res *res; - bool has_cpor, has_cmax, has_cmin; + bool has_cpor, has_cmax, has_cmin, has_intpri; lockdep_assert_cpus_held(); @@ -674,6 +682,7 @@ static void mpam_resctrl_pick_caches(void) has_cpor = cache_has_usable_cpor(class); has_cmax = cache_has_usable_cmax(class); has_cmin = cache_has_usable_cmin(class); + has_intpri = class_has_usable_intpri(cprops); if (class->type != MPAM_CLASS_CACHE) { pr_debug("pick_caches: Class is not a cache\n"); @@ -741,6 +750,17 @@ static void mpam_resctrl_pick_caches(void) } res->class = class; } + + if (has_intpri) { + if (class->level == 2) { + res = &mpam_resctrl_exports[RDT_RESOURCE_L2_PRI]; + res->resctrl_res.name = "L2PRI"; + } else { + res = &mpam_resctrl_exports[RDT_RESOURCE_L3_PRI]; + res->resctrl_res.name = "L3PRI"; + } + res->class = class; + } } srcu_read_unlock(&mpam_srcu, idx); } @@ -748,7 +768,7 @@ static void mpam_resctrl_pick_caches(void) static void mpam_resctrl_pick_mba(void) { struct mpam_resctrl_res *res; - bool has_mba, has_mbw_min; + bool has_mba, has_mbw_min, has_intpri; struct mpam_class *class; int idx; @@ -760,6 +780,7 @@ static void mpam_resctrl_pick_mba(void) has_mba = class_has_usable_mba(cprops); has_mbw_min = class_has_usable_mbw_min(cprops); + has_intpri = class_has_usable_intpri(cprops); if (class->level < 3) continue; @@ -778,6 +799,12 @@ static void mpam_resctrl_pick_mba(void) res->class = class; res->resctrl_res.name = "MBMIN"; } + + if (has_intpri) { + res = &mpam_resctrl_exports[RDT_RESOURCE_MB_PRI]; + res->class = class; + res->resctrl_res.name = "MBPRI"; + } } srcu_read_unlock(&mpam_srcu, idx); } @@ -969,6 +996,35 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) r->alloc_capable = true; break; + case RDT_RESOURCE_L3_PRI: + case RDT_RESOURCE_L2_PRI: + r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; + r->fflags = RFTYPE_RES_CACHE; + r->default_ctrl = GENMASK(cprops->intpri_wd - 1, 0); + r->data_width = 3; + r->cache_level = class->level; + + if (class_has_usable_intpri(cprops)) + r->alloc_capable = true; + + r->membw.min_bw = 0; + r->membw.bw_gran = 1; + break; + + case RDT_RESOURCE_MB_PRI: + r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; + r->fflags = RFTYPE_RES_MB; + r->default_ctrl = GENMASK(cprops->intpri_wd - 1, 0); + r->data_width = 3; + + r->membw.bw_gran = 1; + + if (class_has_usable_intpri(cprops)) + r->alloc_capable = true; + break; + default: break; } @@ -1095,6 +1151,11 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, case RDT_RESOURCE_L3_MIN: configured_by = mpam_feat_cmin; break; + case RDT_RESOURCE_L2_PRI: + case RDT_RESOURCE_L3_PRI: + case RDT_RESOURCE_MB_PRI: + configured_by = mpam_feat_intpri_part; + break; case RDT_RESOURCE_MBA: if (mba_class_use_mbw_part(cprops)) { @@ -1126,6 +1187,8 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, return mbw_max_to_percent(cfg->cmax, cprops->cmax_wd); case mpam_feat_cmin: return mbw_max_to_percent(cfg->cmin, cprops->cmax_wd); + case mpam_feat_intpri_part: + return cfg->intpri; case mpam_feat_mbw_part: /* TODO: Scaling is not yet supported */ return mbw_pbm_to_percent(cfg->mbw_pbm, cprops); @@ -1179,6 +1242,12 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, cfg.cmin = percent_to_mbw_max(cfg_val, cprops->cmax_wd); mpam_set_feature(mpam_feat_cmin, &cfg); break; + case RDT_RESOURCE_L2_PRI: + case RDT_RESOURCE_L3_PRI: + case RDT_RESOURCE_MB_PRI: + cfg.intpri = cfg_val; + mpam_set_feature(mpam_feat_intpri_part, &cfg); + break; case RDT_RESOURCE_MBA: if (mba_class_use_mbw_part(cprops)) { cfg.mbw_pbm = percent_to_mbw_pbm(cfg_val, cprops); diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index 4b0f57ddeb0e..86c5f87c6294 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -133,6 +133,8 @@ struct rdt_domain { * @arch_has_sparse_bitmasks: True if a bitmask like f00f is valid. * @arch_has_per_cpu_cfg: True if QOS_CFG register for this cache * level has CPU scope. + * @intpri_wd: Number of implemented bits in the priority + * partition. */ struct resctrl_cache { unsigned int cbm_len; @@ -140,6 +142,7 @@ struct resctrl_cache { unsigned int shareable_bits; bool arch_has_sparse_bitmasks; bool arch_has_per_cpu_cfg; + unsigned int intpri_wd; }; /** @@ -166,6 +169,8 @@ enum membw_throttle_mode { * different memory bandwidths * @mba_sc: True if MBA software controller(mba_sc) is enabled * @mb_map: Mapping of memory B/W percentage to memory B/W delay + * @intpri_wd: Number of implemented bits in the priority + * partition. */ struct resctrl_membw { u32 min_bw; @@ -175,6 +180,7 @@ struct resctrl_membw { enum membw_throttle_mode throttle_mode; bool mba_sc; u32 *mb_map; + u32 intpri_wd; }; /** diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h index a5c36ffaa0c2..5bce95a53064 100644 --- a/include/linux/resctrl_types.h +++ b/include/linux/resctrl_types.h @@ -83,6 +83,9 @@ enum resctrl_res_level { RDT_RESOURCE_L3_MIN, RDT_RESOURCE_L2_MIN, RDT_RESOURCE_MB_MIN, + RDT_RESOURCE_L3_PRI, + RDT_RESOURCE_L2_PRI, + RDT_RESOURCE_MB_PRI, /* Must be the last */ RDT_NUM_RESOURCES, -- 2.25.1

hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC35SV -------------------------------- Allow users can configure the mata hard-limit feature and cache soft-limit feature by the schemata MBHDL:${domain_id}=${value} interface under the resctrl fs. When MAX bandwidth is exceeded, the hard-limit feature not allows the partition use any more bandwidth until the memory bandwidth measurement for the partition falls below MAX. Signed-off-by: Zeng Heng <zengheng4@huawei.com> --- drivers/platform/mpam/mpam_devices.c | 16 +++++++++-- drivers/platform/mpam/mpam_internal.h | 2 ++ drivers/platform/mpam/mpam_resctrl.c | 40 ++++++++++++++++++++++++++- include/linux/resctrl_types.h | 1 + 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index 0614ae4d382a..814959ac1ed2 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -611,8 +611,10 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris) mpam_set_feature(mpam_feat_mbw_part, props); props->bwa_wd = FIELD_GET(MPAMF_MBW_IDR_BWA_WD, mbw_features); - if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MAX, mbw_features)) + if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MAX, mbw_features)) { mpam_set_feature(mpam_feat_mbw_max, props); + mpam_set_feature(mpam_feat_max_limit, props); + } if (props->bwa_wd && FIELD_GET(MPAMF_MBW_IDR_HAS_MIN, mbw_features)) mpam_set_feature(mpam_feat_mbw_min, props); @@ -1197,6 +1199,7 @@ static void mpam_reset_msc_bitmap(struct mpam_msc *msc, u16 reg, u16 wd) static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, struct mpam_config *cfg) { + bool limit; u32 pri_val = 0; u16 intpri, dspri; u16 cmax = MPAMCFG_CMAX_CMAX; @@ -1250,7 +1253,16 @@ static void mpam_reprogram_ris_partid(struct mpam_msc_ris *ris, u16 partid, if (mpam_has_feature(mpam_feat_mbw_max, rprops)) { if (mpam_has_feature(mpam_feat_mbw_max, cfg)) - mpam_write_partsel_reg(msc, MBW_MAX, cfg->mbw_max | MPAMCFG_MBW_MAX_HARDLIM); + bwa_fract = cfg->mbw_max; + + if (mpam_has_feature(mpam_feat_max_limit, cfg)) + limit = cfg->max_limit; + else + limit = false; + + if (limit) + mpam_write_partsel_reg(msc, MBW_MAX, bwa_fract | + MPAMCFG_MBW_MAX_HARDLIM); else mpam_write_partsel_reg(msc, MBW_MAX, bwa_fract); } diff --git a/drivers/platform/mpam/mpam_internal.h b/drivers/platform/mpam/mpam_internal.h index 47582ddc554f..e9c52078edea 100644 --- a/drivers/platform/mpam/mpam_internal.h +++ b/drivers/platform/mpam/mpam_internal.h @@ -90,6 +90,7 @@ enum mpam_device_features { mpam_feat_mbw_part, mpam_feat_mbw_min, mpam_feat_mbw_max, + mpam_feat_max_limit, mpam_feat_mbw_prop, mpam_feat_intpri_part, mpam_feat_intpri_part_0_low, @@ -164,6 +165,7 @@ struct mpam_config { u32 mbw_pbm; u16 mbw_max; u16 mbw_min; + bool max_limit; u16 cmax; u16 cmin; diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index b4e004281745..67cdcfc9e693 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -566,6 +566,14 @@ static bool class_has_usable_intpri(struct mpam_props *cprops) return false; } +static bool class_has_usable_max_limit(struct mpam_props *cprops) +{ + if (mpam_has_feature(mpam_feat_max_limit, cprops)) + return true; + + return false; +} + /* * Calculate the percentage change from each implemented bit in the control * This can return 0 when BWA_WD is greater than 6. (100 / (1<<7) == 0) @@ -767,8 +775,8 @@ static void mpam_resctrl_pick_caches(void) static void mpam_resctrl_pick_mba(void) { + bool has_mba, has_mbw_min, has_intpri, has_limit; struct mpam_resctrl_res *res; - bool has_mba, has_mbw_min, has_intpri; struct mpam_class *class; int idx; @@ -781,6 +789,7 @@ static void mpam_resctrl_pick_mba(void) has_mba = class_has_usable_mba(cprops); has_mbw_min = class_has_usable_mbw_min(cprops); has_intpri = class_has_usable_intpri(cprops); + has_limit = class_has_usable_max_limit(cprops); if (class->level < 3) continue; @@ -805,6 +814,12 @@ static void mpam_resctrl_pick_mba(void) res->class = class; res->resctrl_res.name = "MBPRI"; } + + if (has_limit) { + res = &mpam_resctrl_exports[RDT_RESOURCE_MB_HDL]; + res->class = class; + res->resctrl_res.name = "MBHDL"; + } } srcu_read_unlock(&mpam_srcu, idx); } @@ -1025,6 +1040,19 @@ static int mpam_resctrl_resource_init(struct mpam_resctrl_res *res) r->alloc_capable = true; break; + case RDT_RESOURCE_MB_HDL: + r->format_str = "%d=%0*u"; + r->schema_fmt = RESCTRL_SCHEMA_PERCENT; + r->fflags = RFTYPE_RES_MB; + r->default_ctrl = 1; + r->data_width = 1; + + r->membw.bw_gran = 1; + + if (class_has_usable_max_limit(cprops)) + r->alloc_capable = true; + break; + default: break; } @@ -1171,6 +1199,10 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, configured_by = mpam_feat_mbw_min; break; + case RDT_RESOURCE_MB_HDL: + configured_by = mpam_feat_max_limit; + break; + default: return -EINVAL; } @@ -1196,6 +1228,8 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, return mbw_max_to_percent(cfg->mbw_max, cprops->bwa_wd); case mpam_feat_mbw_min: return mbw_max_to_percent(cfg->mbw_min, cprops->bwa_wd); + case mpam_feat_max_limit: + return cfg->max_limit; default: return -EINVAL; } @@ -1263,6 +1297,10 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, cfg.mbw_min = percent_to_mbw_max(cfg_val, cprops->bwa_wd); mpam_set_feature(mpam_feat_mbw_min, &cfg); break; + case RDT_RESOURCE_MB_HDL: + cfg.max_limit = cfg_val; + mpam_set_feature(mpam_feat_max_limit, &cfg); + break; default: return -EINVAL; } diff --git a/include/linux/resctrl_types.h b/include/linux/resctrl_types.h index 5bce95a53064..d863e6d94e9a 100644 --- a/include/linux/resctrl_types.h +++ b/include/linux/resctrl_types.h @@ -86,6 +86,7 @@ enum resctrl_res_level { RDT_RESOURCE_L3_PRI, RDT_RESOURCE_L2_PRI, RDT_RESOURCE_MB_PRI, + RDT_RESOURCE_MB_HDL, /* Must be the last */ RDT_NUM_RESOURCES, -- 2.25.1
participants (2)
-
patchwork bot
-
Zeng Heng