Re: [PATCH v6 14/40] arm_mpam: resctrl: Add boilerplate cpuhp and domain allocation
From: James Morse
Date: Thu Mar 26 2026 - 08:25:12 EST
Hi Ben, Gavin,
On 23/03/2026 10:13, Ben Horgan wrote:
> On 3/23/26 06:31, Gavin Shan wrote:
>> On 3/14/26 12:45 AM, Ben Horgan wrote:
>>> From: James Morse <james.morse@xxxxxxx>
>>>
>>> resctrl has its own data structures to describe its resources. We can't use
>>> these directly as we play tricks with the 'MBA' resource, picking the MPAM
>>> controls or monitors that best apply. We may export the same component as
>>> both L3 and MBA.
>>>
>>> Add mpam_resctrl_res[] as the array of class->resctrl mappings we are
>>> exporting, and add the cpuhp hooks that allocated and free the resctrl
>>> domain structures. Only the mpam control feature are considered here and
>>> monitor support will be added later.
>>>
>>> While we're here, plumb in a few other obvious things.
>>>
>>> CONFIG_ARM_CPU_RESCTRL is used to allow this code to be built even though
>>> it can't yet be linked against resctrl.
>> With the following two comments addressed. I don't think none of them are critical
>> given the fact that this series has been respinned to v6 and may be ready for Linux
>> v7.1. If there is still a chance for another respin, they may be worthy to be addressed.
>>
>> Reviewed-by: Gavin Shan <gshan@xxxxxxxxxx>
I've picked up the change from your second comment, I assume you're happy to keep this
tag. (otherwise shout!)
>>> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
>>> new file mode 100644
>>> index 000000000000..e698b534e3db
>>> --- /dev/null
>>> +++ b/drivers/resctrl/mpam_resctrl.c
>>> +static struct mpam_resctrl_dom *
>>> +mpam_resctrl_alloc_domain(unsigned int cpu, struct mpam_resctrl_res *res)
>>> +{
>>> + int err;
>>> + struct mpam_resctrl_dom *dom;
>>> + struct rdt_ctrl_domain *ctrl_d;
>>> + struct mpam_class *class = res->class;
>>> + struct mpam_component *comp_iter, *ctrl_comp;
>>> + struct rdt_resource *r = &res->resctrl_res;
>>> +
>>> + lockdep_assert_held(&domain_list_lock);
>>> +
>>> + ctrl_comp = NULL;
>>> + guard(srcu)(&mpam_srcu);
>>> + list_for_each_entry_srcu(comp_iter, &class->components, class_list,
>>> + srcu_read_lock_held(&mpam_srcu)) {
>>> + if (cpumask_test_cpu(cpu, &comp_iter->affinity)) {
>>> + ctrl_comp = comp_iter;
>>> + break;
>>> + }
>>> + }
>>> +
>>> + /* class has no component for this CPU */
>>> + if (WARN_ON_ONCE(!ctrl_comp))
>>> + return ERR_PTR(-EINVAL);
>>> +
>>> + dom = kzalloc_node(sizeof(*dom), GFP_KERNEL, cpu_to_node(cpu));
>>> + if (!dom)
>>> + return ERR_PTR(-ENOMEM);
>>> +
>>> + if (r->alloc_capable) {
>>> + dom->ctrl_comp = ctrl_comp;
>>> +
>>> + ctrl_d = &dom->resctrl_ctrl_dom;
>>> + mpam_resctrl_domain_hdr_init(cpu, ctrl_comp, r->rid, &ctrl_d->hdr);
>>> + ctrl_d->hdr.type = RESCTRL_CTRL_DOMAIN;
>>> + err = resctrl_online_ctrl_domain(r, ctrl_d);
>>> + if (err)
>>> + goto free_domain;
>>> +
>>> + mpam_resctrl_domain_insert(&r->ctrl_domains, &ctrl_d->hdr);
>>> + } else {
>>> + pr_debug("Skipped control domain online - no controls\n");
>>> + }
>>> + return dom;
>> Even though we will never support "r->alloc_capable == false", it's worthy to maintain
>> the consistence in the code level here, meaning @dom needs to be released with a proper
>> error number returned.
>>
>> if (r->alloc_capable) {
>> :
>> } else {
>> pr_debug("Skipped control domain online - no controls\n");
>> err = -EINVAL;
>> goto free_domain;
>> }
>>
>> Alternatively, the check can be done before locating the component from its calss.
>>
>>
>> lockdep_assert_held(&domain_list_lock);
>>
>> if (!r->alloc_capable) {
>> pr_debug("Skipped control domain online - no controls\n");
>> return ERR_PTR(-EINVAL);
>> }
>>
>> ctrl_comp = NULL;
>
> Once monitor support is added later in the series this is no longer an
> error path as monitor only platforms are valid. In order to avoid adding
> a change and then reverting it later in the series I would like to keep
> this as it is.
I've left this as it is - adding the monitoring support builds on top of this.
>>> +int mpam_resctrl_online_cpu(unsigned int cpu)
>>> +{
>>> + struct mpam_resctrl_res *res;
>>> + enum resctrl_res_level rid;
>>> +
>>> + guard(mutex)(&domain_list_lock);
>>> + for_each_mpam_resctrl_control(res, rid) {
>>> + struct mpam_resctrl_dom *dom;
>>> + struct rdt_resource *r = &res->resctrl_res;
>>> +
>>> + if (!res->class)
>>> + continue; // dummy_resource;
>>> +
>>> + dom = mpam_resctrl_get_domain_from_cpu(cpu, res);
>>> + if (!dom) {
>>> + dom = mpam_resctrl_alloc_domain(cpu, res);
>>> + } else {
>>> + if (r->alloc_capable) {
>>> + struct rdt_ctrl_domain *ctrl_d = &dom->resctrl_ctrl_dom;
>>> +
>>> + mpam_resctrl_online_domain_hdr(cpu, &ctrl_d->hdr);
>>> + }
>>> + }
>>> + if (IS_ERR(dom))
>>> + return PTR_ERR(dom);
>>> + }
>>> +
>>
>> I think the "if (IS_ERR(dom))" check can be moved after "dom = mpam_resctrl_alloc_domain(cpu, res)"
>> because it seems the only path where an erroneous domain can be returned.
>>
>> dom = mpam_resctrl_get_domain_from_cpu(cpu, res);
>> if (!dom) {
>> dom = mpam_resctrl_alloc_domain(cpu, res);
>> if (IS_ERR(dom))
>> return PTR_ERR(dom);
>> } else {
>> ...
>> }
>
> Yes, that would be clearer. I'll make this change if a respin becomes needed.
Applied locally.
Thanks!
James