fs/resctrl: Add the functionality to assign MBM events

When supported, "mbm_event" counter assignment mode offers "num_mbm_cntrs"
number of counters that can be assigned to RMID, event pairs and monitor
bandwidth usage as long as it is assigned.

Add the functionality to allocate and assign a counter to an RMID, event
pair in the domain. Also, add the helper rdtgroup_assign_cntrs() to assign
counters in the group.

Log the error message "Failed to allocate counter for <event> in domain
<id>" in /sys/fs/resctrl/info/last_cmd_status if all the counters are in
use. Exit on the first failure when assigning counters across all the
domains.

Signed-off-by: Babu Moger <babu.moger@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Reviewed-by: Reinette Chatre <reinette.chatre@intel.com>
Link: https://lore.kernel.org/cover.1757108044.git.babu.moger@amd.com
This commit is contained in:
Babu Moger
2025-09-05 16:34:16 -05:00
committed by Borislav Petkov (AMD)
parent f7a4fb2231
commit bd85310efd
2 changed files with 158 additions and 0 deletions

View File

@@ -396,6 +396,8 @@ int resctrl_num_mbm_cntrs_show(struct kernfs_open_file *of, struct seq_file *s,
int resctrl_available_mbm_cntrs_show(struct kernfs_open_file *of, struct seq_file *s,
void *v);
void rdtgroup_assign_cntrs(struct rdtgroup *rdtgrp);
#ifdef CONFIG_RESCTRL_FS_PSEUDO_LOCK
int rdtgroup_locksetup_enter(struct rdtgroup *rdtgrp);

View File

@@ -356,6 +356,55 @@ static struct mbm_state *get_mbm_state(struct rdt_mon_domain *d, u32 closid,
return state ? &state[idx] : NULL;
}
/*
* mbm_cntr_get() - Return the counter ID for the matching @evtid and @rdtgrp.
*
* Return:
* Valid counter ID on success, or -ENOENT on failure.
*/
static int mbm_cntr_get(struct rdt_resource *r, struct rdt_mon_domain *d,
struct rdtgroup *rdtgrp, enum resctrl_event_id evtid)
{
int cntr_id;
if (!r->mon.mbm_cntr_assignable)
return -ENOENT;
if (!resctrl_is_mbm_event(evtid))
return -ENOENT;
for (cntr_id = 0; cntr_id < r->mon.num_mbm_cntrs; cntr_id++) {
if (d->cntr_cfg[cntr_id].rdtgrp == rdtgrp &&
d->cntr_cfg[cntr_id].evtid == evtid)
return cntr_id;
}
return -ENOENT;
}
/*
* mbm_cntr_alloc() - Initialize and return a new counter ID in the domain @d.
* Caller must ensure that the specified event is not assigned already.
*
* Return:
* Valid counter ID on success, or -ENOSPC on failure.
*/
static int mbm_cntr_alloc(struct rdt_resource *r, struct rdt_mon_domain *d,
struct rdtgroup *rdtgrp, enum resctrl_event_id evtid)
{
int cntr_id;
for (cntr_id = 0; cntr_id < r->mon.num_mbm_cntrs; cntr_id++) {
if (!d->cntr_cfg[cntr_id].rdtgrp) {
d->cntr_cfg[cntr_id].rdtgrp = rdtgrp;
d->cntr_cfg[cntr_id].evtid = evtid;
return cntr_id;
}
}
return -ENOSPC;
}
static int __mon_event_count(u32 closid, u32 rmid, struct rmid_read *rr)
{
int cpu = smp_processor_id();
@@ -887,6 +936,113 @@ u32 resctrl_get_mon_evt_cfg(enum resctrl_event_id evtid)
return mon_event_all[evtid].evt_cfg;
}
/*
* rdtgroup_assign_cntr() - Assign/unassign the counter ID for the event, RMID
* pair in the domain.
*
* Assign the counter if @assign is true else unassign the counter. Reset the
* associated non-architectural state.
*/
static void rdtgroup_assign_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
enum resctrl_event_id evtid, u32 rmid, u32 closid,
u32 cntr_id, bool assign)
{
struct mbm_state *m;
resctrl_arch_config_cntr(r, d, evtid, rmid, closid, cntr_id, assign);
m = get_mbm_state(d, closid, rmid, evtid);
if (m)
memset(m, 0, sizeof(*m));
}
/*
* rdtgroup_alloc_assign_cntr() - Allocate a counter ID and assign it to the event
* pointed to by @mevt and the resctrl group @rdtgrp within the domain @d.
*
* Return:
* 0 on success, < 0 on failure.
*/
static int rdtgroup_alloc_assign_cntr(struct rdt_resource *r, struct rdt_mon_domain *d,
struct rdtgroup *rdtgrp, struct mon_evt *mevt)
{
int cntr_id;
/* No action required if the counter is assigned already. */
cntr_id = mbm_cntr_get(r, d, rdtgrp, mevt->evtid);
if (cntr_id >= 0)
return 0;
cntr_id = mbm_cntr_alloc(r, d, rdtgrp, mevt->evtid);
if (cntr_id < 0) {
rdt_last_cmd_printf("Failed to allocate counter for %s in domain %d\n",
mevt->name, d->hdr.id);
return cntr_id;
}
rdtgroup_assign_cntr(r, d, mevt->evtid, rdtgrp->mon.rmid, rdtgrp->closid, cntr_id, true);
return 0;
}
/*
* rdtgroup_assign_cntr_event() - Assign a hardware counter for the event in
* @mevt to the resctrl group @rdtgrp. Assign counters to all domains if @d is
* NULL; otherwise, assign the counter to the specified domain @d.
*
* If all counters in a domain are already in use, rdtgroup_alloc_assign_cntr()
* will fail. The assignment process will abort at the first failure encountered
* during domain traversal, which may result in the event being only partially
* assigned.
*
* Return:
* 0 on success, < 0 on failure.
*/
static int rdtgroup_assign_cntr_event(struct rdt_mon_domain *d, struct rdtgroup *rdtgrp,
struct mon_evt *mevt)
{
struct rdt_resource *r = resctrl_arch_get_resource(mevt->rid);
int ret = 0;
if (!d) {
list_for_each_entry(d, &r->mon_domains, hdr.list) {
ret = rdtgroup_alloc_assign_cntr(r, d, rdtgrp, mevt);
if (ret)
return ret;
}
} else {
ret = rdtgroup_alloc_assign_cntr(r, d, rdtgrp, mevt);
}
return ret;
}
/*
* rdtgroup_assign_cntrs() - Assign counters to MBM events. Called when
* a new group is created.
*
* Each group can accommodate two counters per domain: one for the total
* event and one for the local event. Assignments may fail due to the limited
* number of counters. However, it is not necessary to fail the group creation
* and thus no failure is returned. Users have the option to modify the
* counter assignments after the group has been created.
*/
void rdtgroup_assign_cntrs(struct rdtgroup *rdtgrp)
{
struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3);
if (!r->mon_capable || !resctrl_arch_mbm_cntr_assign_enabled(r))
return;
if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
rdtgroup_assign_cntr_event(NULL, rdtgrp,
&mon_event_all[QOS_L3_MBM_TOTAL_EVENT_ID]);
if (resctrl_is_mon_event_enabled(QOS_L3_MBM_LOCAL_EVENT_ID))
rdtgroup_assign_cntr_event(NULL, rdtgrp,
&mon_event_all[QOS_L3_MBM_LOCAL_EVENT_ID]);
}
int resctrl_mbm_assign_mode_show(struct kernfs_open_file *of,
struct seq_file *s, void *v)
{