Support MATA monitor feature for MPAM
Zeng Heng (7): arm64/mpam: Support MATA monitor feature for MPAM arm64/mpam: Add judgment to distinguish MSMON_MBWU_CAPTURE definition arm64/mpam: fix MBA granularity conversion formula arm64/mpam: fix bug in percent_to_mbw_max() arm64/mpam: Fix out-of-bound access of mbwu_state array arm64/mpam: Fix out-of-bound access of cfg array arm64/mpam: Improve conversion accuracy between percent and fixed-point fraction
arch/x86/kernel/cpu/resctrl/monitor.c | 53 ++++++++++ drivers/platform/mpam/mpam_devices.c | 31 ++++-- drivers/platform/mpam/mpam_resctrl.c | 138 +++++++++++++++++++++----- fs/resctrl/internal.h | 15 --- fs/resctrl/monitor.c | 47 +-------- include/linux/resctrl.h | 17 ++++ 6 files changed, 208 insertions(+), 93 deletions(-)
-- 2.25.1
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/14980 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/X...
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/14980 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/X...
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8T2RT
--------------------------------
To support the MB monitoring feature, provide mbm_total_bytes interface under the resctrl fs to monitor the MATA memory bandwidth.
In fact, resctrl does not mandate that MBM should work in the mode of free running, so even if the number of monitor instances doesn't meet the number of resctrl has control/monitor groups, it will not affect the monitoring function.
Fixes: dc2005d467b3 ("untested: arm_mpam: resctrl: Add support for mbm counters") Signed-off-by: Zeng Heng zengheng4@huawei.com --- arch/x86/kernel/cpu/resctrl/monitor.c | 53 +++++++++++++++++++ drivers/platform/mpam/mpam_resctrl.c | 76 ++++++++++++++++++++++++--- fs/resctrl/internal.h | 15 ------ fs/resctrl/monitor.c | 47 +---------------- include/linux/resctrl.h | 17 ++++++ 5 files changed, 139 insertions(+), 69 deletions(-)
diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c index 54cf311b6de4..9bb08920985b 100644 --- a/arch/x86/kernel/cpu/resctrl/monitor.c +++ b/arch/x86/kernel/cpu/resctrl/monitor.c @@ -267,3 +267,56 @@ void __init intel_rdt_mbm_apply_quirk(void) mbm_cf_rmidthreshold = mbm_cf_table[cf_index].rmidthreshold; mbm_cf = mbm_cf_table[cf_index].cf; } + +static struct mon_evt llc_occupancy_event = { + .name = "llc_occupancy", + .evtid = QOS_L3_OCCUP_EVENT_ID, +}; + +static struct mon_evt mbm_total_event = { + .name = "mbm_total_bytes", + .evtid = QOS_L3_MBM_TOTAL_EVENT_ID, +}; + +static struct mon_evt mbm_local_event = { + .name = "mbm_local_bytes", + .evtid = QOS_L3_MBM_LOCAL_EVENT_ID, +}; + +/* + * Initialize the event list for the resource. + * + * Note that MBM events are also part of RDT_RESOURCE_L3 resource + * because as per the SDM the total and local memory bandwidth + * are enumerated as part of L3 monitoring. + */ +static void l3_mon_evt_init(struct rdt_resource *r) +{ + INIT_LIST_HEAD(&r->evt_list); + + if (resctrl_arch_is_llc_occupancy_enabled()) + list_add_tail(&llc_occupancy_event.list, &r->evt_list); + if (resctrl_arch_is_mbm_total_enabled()) + list_add_tail(&mbm_total_event.list, &r->evt_list); + if (resctrl_arch_is_mbm_local_enabled()) + list_add_tail(&mbm_local_event.list, &r->evt_list); +} + +static int resctrl_arch_mon_resource_init(void) +{ + struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3); + int ret; + + l3_mon_evt_init(r); + + if (resctrl_arch_is_evt_configurable(QOS_L3_MBM_TOTAL_EVENT_ID)) { + mbm_total_event.configurable = true; + mbm_config_rftype_init("mbm_total_bytes_config"); + } + if (resctrl_arch_is_evt_configurable(QOS_L3_MBM_LOCAL_EVENT_ID)) { + mbm_local_event.configurable = true; + mbm_config_rftype_init("mbm_local_bytes_config"); + } + + return 0; +} diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 38e53c46a9ec..035232198541 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -473,14 +473,6 @@ static bool class_has_usable_mbwu(struct mpam_class *class) if (!mpam_has_feature(mpam_feat_msmon_mbwu, cprops)) return false;
- /* - * resctrl expects the bandwidth counters to be free running, - * which means we need as many monitors as resctrl has - * control/monitor groups. - */ - if (cprops->num_mbwu_mon < resctrl_arch_system_num_rmid_idx()) - return false; - return (mpam_partid_max > 1) || (mpam_pmg_max != 0); }
@@ -1199,6 +1191,74 @@ int mpam_resctrl_offline_cpu(unsigned int cpu) return 0; }
+static struct mon_evt llc_occupancy_event = { + .name = "llc_occupancy", + .evtid = QOS_L3_OCCUP_EVENT_ID, +}; + +static struct mon_evt mbm_total_event = { + .name = "mbm_total_bytes", + .evtid = QOS_L3_MBM_TOTAL_EVENT_ID, +}; + +static struct mon_evt mbm_local_event = { + .name = "mbm_local_bytes", + .evtid = QOS_L3_MBM_LOCAL_EVENT_ID, +}; + +/* + * Initialize the event list for the resource. + * + * Note that MBM events are also part of RDT_RESOURCE_L3 resource + * because as per the SDM the total and local memory bandwidth + * are enumerated as part of L3 monitoring. + */ +static void l3_mon_evt_init(struct rdt_resource *r) +{ + INIT_LIST_HEAD(&r->evt_list); + + if ((r->rid == RDT_RESOURCE_L3) && + resctrl_arch_is_llc_occupancy_enabled()) { + list_add_tail(&llc_occupancy_event.list, &r->evt_list); + + if (resctrl_arch_is_mbm_local_enabled()) + list_add_tail(&mbm_local_event.list, &r->evt_list); + } + + if ((r->rid == RDT_RESOURCE_MBA) && + resctrl_arch_is_mbm_total_enabled()) + list_add_tail(&mbm_total_event.list, &r->evt_list); +} + +static int __resctrl_mon_resource_init(enum resctrl_res_level res) +{ + struct rdt_resource *r = resctrl_arch_get_resource(res); + + if (!r->mon_capable) + return 0; + + l3_mon_evt_init(r); + + if ((r->rid == RDT_RESOURCE_MBA) && + resctrl_arch_is_evt_configurable(QOS_L3_MBM_TOTAL_EVENT_ID)) { + mbm_total_event.configurable = true; + mbm_config_rftype_init("mbm_total_bytes_config"); + } + if (resctrl_arch_is_evt_configurable(QOS_L3_MBM_LOCAL_EVENT_ID)) { + mbm_local_event.configurable = true; + mbm_config_rftype_init("mbm_local_bytes_config"); + } + + return 0; +} + +int resctrl_arch_mon_resource_init(void) +{ + __resctrl_mon_resource_init(RDT_RESOURCE_L3); + __resctrl_mon_resource_init(RDT_RESOURCE_MBA); + return 0; +} + static int __init __cacheinfo_ready(void) { cacheinfo_ready = true; diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h index 7a6f46b4edd0..fb620beba958 100644 --- a/fs/resctrl/internal.h +++ b/fs/resctrl/internal.h @@ -66,20 +66,6 @@ static inline struct rdt_fs_context *rdt_fc2context(struct fs_context *fc) return container_of(kfc, struct rdt_fs_context, kfc); }
-/** - * struct mon_evt - Entry in the event list of a resource - * @evtid: event id - * @name: name of the event - * @configurable: true if the event is configurable - * @list: entry in &rdt_resource->evt_list - */ -struct mon_evt { - enum resctrl_event_id evtid; - char *name; - bool configurable; - struct list_head list; -}; - /** * union mon_data_bits - Monitoring details for each event file * @priv: Used to store monitoring event data in @u @@ -306,7 +292,6 @@ void cqm_setup_limbo_handler(struct rdt_domain *dom, unsigned long delay_ms, void cqm_handle_limbo(struct work_struct *work); bool has_busy_rmid(struct rdt_domain *d); void __check_limbo(struct rdt_domain *d, bool force_free); -void mbm_config_rftype_init(const char *config); void rdt_staged_configs_clear(void); int resctrl_find_cleanest_closid(void);
diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c index 68401ca0827a..7d824dc8fa90 100644 --- a/fs/resctrl/monitor.c +++ b/fs/resctrl/monitor.c @@ -791,40 +791,6 @@ static void dom_data_exit(struct rdt_resource *r) mutex_unlock(&rdtgroup_mutex); }
-static struct mon_evt llc_occupancy_event = { - .name = "llc_occupancy", - .evtid = QOS_L3_OCCUP_EVENT_ID, -}; - -static struct mon_evt mbm_total_event = { - .name = "mbm_total_bytes", - .evtid = QOS_L3_MBM_TOTAL_EVENT_ID, -}; - -static struct mon_evt mbm_local_event = { - .name = "mbm_local_bytes", - .evtid = QOS_L3_MBM_LOCAL_EVENT_ID, -}; - -/* - * Initialize the event list for the resource. - * - * Note that MBM events are also part of RDT_RESOURCE_L3 resource - * because as per the SDM the total and local memory bandwidth - * are enumerated as part of L3 monitoring. - */ -static void l3_mon_evt_init(struct rdt_resource *r) -{ - INIT_LIST_HEAD(&r->evt_list); - - if (resctrl_arch_is_llc_occupancy_enabled()) - list_add_tail(&llc_occupancy_event.list, &r->evt_list); - if (resctrl_arch_is_mbm_total_enabled()) - list_add_tail(&mbm_total_event.list, &r->evt_list); - if (resctrl_arch_is_mbm_local_enabled()) - list_add_tail(&mbm_local_event.list, &r->evt_list); -} - int resctrl_mon_resource_init(void) { struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3); @@ -837,18 +803,7 @@ int resctrl_mon_resource_init(void) if (ret) return ret;
- l3_mon_evt_init(r); - - if (resctrl_arch_is_evt_configurable(QOS_L3_MBM_TOTAL_EVENT_ID)) { - mbm_total_event.configurable = true; - mbm_config_rftype_init("mbm_total_bytes_config"); - } - if (resctrl_arch_is_evt_configurable(QOS_L3_MBM_LOCAL_EVENT_ID)) { - mbm_local_event.configurable = true; - mbm_config_rftype_init("mbm_local_bytes_config"); - } - - return 0; + return resctrl_arch_mon_resource_init(); }
void resctrl_mon_resource_exit(void) diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h index f4aeccd78afb..edc7264a8369 100644 --- a/include/linux/resctrl.h +++ b/include/linux/resctrl.h @@ -254,6 +254,20 @@ struct resctrl_mon_config_info { int err; };
+/** + * struct mon_evt - Entry in the event list of a resource + * @evtid: event id + * @name: name of the event + * @configurable: true if the event is configurable + * @list: entry in &rdt_resource->evt_list + */ +struct mon_evt { + enum resctrl_event_id evtid; + char *name; + bool configurable; + struct list_head list; +}; + /* * Update and re-load this CPUs defaults. Called via IPI, takes a pointer to * struct resctrl_cpu_sync, or NULL. @@ -405,4 +419,7 @@ extern unsigned int resctrl_rmid_realloc_limit; int resctrl_init(void); void resctrl_exit(void);
+int resctrl_arch_mon_resource_init(void); +void mbm_config_rftype_init(const char *config); + #endif /* _RESCTRL_H */
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8T2RT
--------------------------------
Because MSMON_MBWU_CAPTURE register is implemented in different definition according to the corresponding versions of the protocol. This would affect mbm_total_bytes interface returns the various result.
Consequently, it is necessary to determine the specification definition followed by according to the chip model.
Fixes: 21ac9fc8f275 ("arm_mpam: Track bandwidth counter state for overflow and power management") Signed-off-by: Zeng Heng zengheng4@huawei.com --- drivers/platform/mpam/mpam_devices.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index 19bd40814685..719c8d404526 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -915,6 +915,12 @@ static u64 mpam_msmon_overflow_val(struct mpam_msc_ris *ris) return GENMASK_ULL(30, 0); }
+static const struct midr_range mbwu_flowrate_list[] = { + MIDR_ALL_VERSIONS(MIDR_HISI_TSV110), + MIDR_ALL_VERSIONS(MIDR_HISI_LINXICORE9100), + { /* sentinel */ } +}; + static void __ris_msmon_read(void *arg) { bool nrdy = false; @@ -986,6 +992,18 @@ static void __ris_msmon_read(void *arg) if (!mbwu_state) break;
+ /* + * Following the definition of the DDI0598 version, + * the value field of MPAM Memory Bandwidth Usage Monitor Register + * indicates the memory bandwidth usage in bytes per second, + * instead the scaled count of bytes transferred since the monitor + * was last reset in the latest version (DDI0598D_b). + */ + if (ris->comp->class->type == MPAM_CLASS_MEMORY) { + if (is_midr_in_range_list(read_cpuid_id(), mbwu_flowrate_list)) + break; + } + /* Add any pre-overflow value to the mbwu_state->val */ if (mbwu_state->prev_val > now) overflow_val = mpam_msmon_overflow_val(ris) - mbwu_state->prev_val;
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8T2RT
--------------------------------
Correct MBA granularity conversion formula.
Fixes: 58db5c68e84a ("untested: arm_mpam: resctrl: Add support for MB resource") Signed-off-by: Zeng Heng zengheng4@huawei.com --- drivers/platform/mpam/mpam_resctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 035232198541..a0b555b581f3 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -505,7 +505,7 @@ static u32 get_mba_granularity(struct mpam_props *cprops) * bwa_wd is the number of bits implemented in the 0.xxx * fixed point fraction. 1 bit is 50%, 2 is 25% etc. */ - return MAX_MBA_BW / (cprops->bwa_wd + 1); + return MAX_MBA_BW / (1 << cprops->bwa_wd); }
return 0;
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8T2RT
--------------------------------
Correct percentage to fixed floating point conversion formula.
Fixes: 58db5c68e84a ("untested: arm_mpam: resctrl: Add support for MB resource") Signed-off-by: Zeng Heng zengheng4@huawei.com --- drivers/platform/mpam/mpam_resctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index a0b555b581f3..59395d40d7ec 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -567,7 +567,7 @@ static u16 percent_to_mbw_max(u8 pc, struct mpam_props *cprops) break; }
- value &= GENMASK(15, 15 - cprops->bwa_wd); + value &= GENMASK(15, 15 - cprops->bwa_wd + 1);
return value; }
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAFGJ6
---------------------------------------------------
The mbwu_state array is allocated according to the monitor number. However when select the monitor the index is encoded by closid and rmid, which may exceed the monitor number.
If the KASAN config is enabled, we would find the following error when create new monitors: BUG: KASAN: slab-use-after-free in mpam_msmon_reset_mbwu+0x3b8/0x450 Write of size 1 at addr ffff0800c2350fa1 by task kworker/0:0/8
In addition, the statistics of mbwu monitors are cumulative values, which are different type with csu monitors, so need to make sure use the same monitor between twice readings.
Here we adapt the remainder of rmid to the num_mbwu_mon as a compromise, if the mbwu monitor number of system can't support free run mode.
Fixes: dc2005d467b3 ("untested: arm_mpam: resctrl: Add support for mbm counters") Signed-off-by: Zeng Heng zengheng4@huawei.com --- drivers/platform/mpam/mpam_resctrl.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 59395d40d7ec..31b374d47a42 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -336,8 +336,10 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d, { int err; u64 cdp_val; + u16 num_mbwu_mon; struct mon_cfg cfg; struct mpam_resctrl_dom *dom; + struct mpam_resctrl_res *res; u32 mon = *(u32 *)arch_mon_ctx; enum mpam_device_features type;
@@ -358,8 +360,16 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d, }
cfg.mon = mon; - if (cfg.mon == USE_RMID_IDX) - cfg.mon = resctrl_arch_rmid_idx_encode(closid, rmid); + if (cfg.mon == USE_RMID_IDX) { + /* + * The number of mbwu monitors can't support free run mode, + * adapt the remainder of rmid to the num_mbwu_mon as a + * compromise. + */ + res = container_of(r, struct mpam_resctrl_res, resctrl_res); + num_mbwu_mon = res->class->props.num_mbwu_mon; + cfg.mon = resctrl_arch_rmid_idx_encode(closid, rmid) % num_mbwu_mon; + }
cfg.match_pmg = true; cfg.pmg = rmid; @@ -386,13 +396,17 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain *d, void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_domain *d, u32 closid, u32 rmid, enum resctrl_event_id eventid) { + u16 num_mbwu_mon; struct mon_cfg cfg; struct mpam_resctrl_dom *dom; + struct mpam_resctrl_res *res;
if (eventid != QOS_L3_MBM_LOCAL_EVENT_ID) return;
- cfg.mon = resctrl_arch_rmid_idx_encode(closid, rmid); + res = container_of(r, struct mpam_resctrl_res, resctrl_res); + num_mbwu_mon = res->class->props.num_mbwu_mon; + cfg.mon = resctrl_arch_rmid_idx_encode(closid, rmid) % num_mbwu_mon; cfg.match_pmg = true; cfg.pmg = rmid;
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAFGJ6
--------------------------------
The cfg array of per msc component is allocated according to the partid number. The length of array should be (mpam_partid_max + 1) instead of mpam_partid_max. Otherwise, when resctrl_arch_get_config() accesses the array would raise slab-out-of-bounds fault like below:
BUG: KASAN: slab-out-of-bounds in resctrl_arch_get_config+0x404/0x7c8 Read of size 4 at addr ffff08280da29b64 by task mkdir/4156
Fixes: be74872ad2e3 ("arm_mpam: Allow configuration to be applied and restored during cpu online") Signed-off-by: Zeng Heng zengheng4@huawei.com --- drivers/platform/mpam/mpam_devices.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/platform/mpam/mpam_devices.c b/drivers/platform/mpam/mpam_devices.c index 719c8d404526..5ffa3cc8fb82 100644 --- a/drivers/platform/mpam/mpam_devices.c +++ b/drivers/platform/mpam/mpam_devices.c @@ -1247,7 +1247,7 @@ struct reprogram_ris { /* Call with MSC lock held */ static int mpam_reprogram_ris(void *_arg) { - u16 partid, partid_max; + u16 partid, num_partid; struct reprogram_ris *arg = _arg; struct mpam_msc_ris *ris = arg->ris; struct mpam_config *cfg = arg->cfg; @@ -1256,9 +1256,9 @@ static int mpam_reprogram_ris(void *_arg) return 0;
spin_lock(&partid_max_lock); - partid_max = mpam_partid_max; + num_partid = resctrl_arch_get_num_closid(NULL); spin_unlock(&partid_max_lock); - for (partid = 0; partid < partid_max; partid++) + for (partid = 0; partid < num_partid; partid++) mpam_reprogram_ris_partid(ris, partid, cfg);
return 0; @@ -1414,7 +1414,7 @@ static void mpam_reprogram_msc(struct mpam_msc *msc) }
reset = true; - for (partid = 0; partid < mpam_partid_max; partid++) { + for (partid = 0; partid < resctrl_arch_get_num_closid(NULL); partid++) { cfg = &ris->comp->cfg[partid]; if (cfg->features) reset = false; @@ -2117,7 +2117,8 @@ static int __allocate_component_cfg(struct mpam_component *comp) if (comp->cfg) return 0;
- comp->cfg = kcalloc(mpam_partid_max, sizeof(*comp->cfg), GFP_KERNEL); + comp->cfg = kcalloc(resctrl_arch_get_num_closid(NULL), + sizeof(*comp->cfg), GFP_KERNEL); if (!comp->cfg) return -ENOMEM;
@@ -2229,7 +2230,7 @@ void mpam_reset_class(struct mpam_class *class)
idx = srcu_read_lock(&mpam_srcu); list_for_each_entry_rcu(comp, &class->components, class_list) { - memset(comp->cfg, 0, (mpam_partid_max * sizeof(*comp->cfg))); + memset(comp->cfg, 0, resctrl_arch_get_num_closid(NULL) * sizeof(*comp->cfg));
list_for_each_entry_rcu(ris, &comp->ris, comp_list) { mutex_lock(&ris->msc->lock);
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAKAKN
--------------------------------
According to the bit width of the fixed-point fraction implemented by hardware, the maximum supported precision is calculated to reduce the conversion granularity as much as possible, so that improving conversion accuracy between percent and fixed-point fraction.
Fixes: 58db5c68e84a ("untested: arm_mpam: resctrl: Add support for MB resource") Signed-off-by: Zeng Heng zengheng4@huawei.com --- drivers/platform/mpam/mpam_resctrl.c | 40 ++++++++++++++++++---------- 1 file changed, 26 insertions(+), 14 deletions(-)
diff --git a/drivers/platform/mpam/mpam_resctrl.c b/drivers/platform/mpam/mpam_resctrl.c index 31b374d47a42..b101facbc44d 100644 --- a/drivers/platform/mpam/mpam_resctrl.c +++ b/drivers/platform/mpam/mpam_resctrl.c @@ -536,21 +536,31 @@ static u32 mbw_pbm_to_percent(unsigned long mbw_pbm, struct mpam_props *cprops) return result; }
-static u32 mbw_max_to_percent(u16 mbw_max, struct mpam_props *cprops) +static int get_wd_precision(u8 wd) +{ + int ret = (1 << wd) / MAX_MBA_BW; + + if (!ret) + return 1; + + return ret; +} + +static u32 mbw_max_to_percent(u16 mbw_max, u8 wd) { u8 bit; - u32 divisor = 2, value = 0; + u32 divisor = 2, value = 0, precision = get_wd_precision(wd);
for (bit = 15; bit; bit--) { if (mbw_max & BIT(bit)) - value += MAX_MBA_BW / divisor; + value += MAX_MBA_BW * precision / divisor; divisor <<= 1; }
- return value; + return DIV_ROUND_UP(value, precision); }
-static u32 percent_to_mbw_pbm(u8 pc, struct mpam_props *cprops) +static u32 percent_to_mbw_pbm(u32 pc, struct mpam_props *cprops) { u32 granularity = get_mba_granularity(cprops); u8 num_bits = pc / granularity; @@ -562,26 +572,28 @@ static u32 percent_to_mbw_pbm(u8 pc, struct mpam_props *cprops) return (1 << num_bits) - 1; }
-static u16 percent_to_mbw_max(u8 pc, struct mpam_props *cprops) +static u16 percent_to_mbw_max(u32 pc, u8 wd) { u8 bit; - u32 divisor = 2, value = 0; + u32 divisor = 2, value = 0, precision = get_wd_precision(wd);
- if (WARN_ON_ONCE(cprops->bwa_wd > 15)) + if (WARN_ON_ONCE(wd > 15)) return MAX_MBA_BW;
+ pc *= precision; + for (bit = 15; bit; bit--) { - if (pc >= MAX_MBA_BW / divisor) { - pc -= MAX_MBA_BW / divisor; + if (pc >= MAX_MBA_BW * precision / divisor) { + pc -= MAX_MBA_BW * precision / divisor; value |= BIT(bit); } divisor <<= 1;
- if (!pc || !(MAX_MBA_BW / divisor)) + if (!pc || !(MAX_MBA_BW * precision / divisor)) break; }
- value &= GENMASK(15, 15 - cprops->bwa_wd + 1); + value &= GENMASK(15, 15 - wd + 1);
return value; } @@ -947,7 +959,7 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_domain *d, /* 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); + return mbw_max_to_percent(cfg->mbw_max, cprops->bwa_wd); default: return -EINVAL; } @@ -989,7 +1001,7 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_domain *d, mpam_set_feature(mpam_feat_mbw_part, &cfg); break; } else if (mpam_has_feature(mpam_feat_mbw_max, cprops)) { - cfg.mbw_max = percent_to_mbw_max(cfg_val, cprops); + cfg.mbw_max = percent_to_mbw_max(cfg_val, cprops->bwa_wd); mpam_set_feature(mpam_feat_mbw_max, &cfg); break; }