mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Reinette Chatre <reinette.chatre@intel.com>
To: "Drew Fustini" <fustini@kernel.org>,
	"Adrien Ricciardi" <aricciardi@baylibre.com>,
	"Alexandre Ghiti" <alex@ghiti.fr>,
	"Albert Ou" <aou@eecs.berkeley.edu>,
	"Atish Kumar Patra" <atishp@rivosinc.com>,
	"Atish Patra" <atish.patra@linux.dev>,
	"Babu Moger" <babu.moger@amd.com>,
	"Ben Horgan" <ben.horgan@arm.com>,
	"Borislav Petkov" <bp@alien8.de>,
	"Chen Pei" <cp0613@linux.alibaba.com>,
	"Conor Dooley" <conor.dooley@microchip.com>,
	"Conor Dooley" <conor+dt@kernel.org>,
	"Dave Hansen" <dave.hansen@linux.intel.com>,
	"Dave Martin" <Dave.Martin@arm.com>,
	"Fenghua Yu" <fenghuay@nvidia.com>,
	"Gong Shuai" <gong.shuai@sanechips.com.cn>,
	"Gong Shuai" <gsh517@gmail.com>,
	guo.wenjia23@zte.com.cn, "James Morse" <james.morse@arm.com>,
	"Kornel Dulęba" <mindal@semihalf.com>,
	"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
	liu.qingtao2@zte.com.cn,
	"Liu Zhiwei" <zhiwei_liu@linux.alibaba.com>,
	"Palmer Dabbelt" <palmer@dabbelt.com>,
	"Paul Walmsley" <pjw@kernel.org>,
	"Peter Newman" <peternewman@google.com>,
	"Radim Krčmář" <rkrcmar@ventanamicro.com>,
	"Rob Herring" <robh@kernel.org>,
	"Samuel Holland" <samuel.holland@sifive.com>,
	"Sebastian Andrzej Siewior" <bigeasy@linutronix.de>,
	"Clark Williams" <clrkwllms@kernel.org>,
	"Steven Rostedt" <rostedt@goodmis.org>,
	"Tony Luck" <tony.luck@intel.com>,
	"Vasudevan Srinivasan" <vasu@rivosinc.com>,
	"Ved Shanbhogue" <ved@rivosinc.com>,
	"Weiwei Li" <liwei1518@gmail.com>,
	"yunhui cui" <cuiyunhui@bytedance.com>,
	"Zhanpeng Zhang" <zhangzhanpeng.jasper@bytedance.com>
Cc: <linux-kernel@vger.kernel.org>, <linux-riscv@lists.infradead.org>,
	<x86@kernel.org>, <devicetree@vger.kernel.org>,
	<linux-rt-devel@lists.linux.dev>, <linux-doc@vger.kernel.org>
Subject: Re: [PATCH v8 2/5] riscv_cbqri: resctrl: Add cache allocation via capacity block mask
Date: Thu, 17 Sep 2026 17:54:35 -0700	[thread overview]
Message-ID: <fb4813cf-b21e-43ca-9bd4-4b42d2214aa6@intel.com> (raw)
In-Reply-To: <20260917-dfustini-atl-sc-cbqri-dt-v8-2-7964e8d73fe8@kernel.org>

Hi Drew,

On 9/17/26 9:39 AM, Drew Fustini wrote:
> diff --git a/arch/riscv/include/asm/resctrl.h b/arch/riscv/include/asm/resctrl.h
> new file mode 100644
> index 000000000000..b08f4e12f7aa
> --- /dev/null
> +++ b/arch/riscv/include/asm/resctrl.h

...

> +/**
> + * resctrl_arch_alloc_capable() - any CBQRI controller exposes resctrl alloc
> + *
> + * Returns true once at least one CBQRI controller has successfully probed for
> + * a resctrl-exposed cache capacity allocation feature. Only meaningful after
> + * cbqri_resctrl_setup() runs at late_initcall.
> + */
> +bool resctrl_arch_alloc_capable(void);
> +
> +/**
> + * resctrl_arch_mon_capable() - any CBQRI controller exposes resctrl monitoring
> + *
> + * The CBQRI driver implements capacity allocation only and wires up no
> + * monitoring events, so this always returns false. fs/resctrl references it
> + * unconditionally, hence the stub.
> + */
> +bool resctrl_arch_mon_capable(void);
> +

fyi ... I aim to comment more details later in this patch but for now please note that
there are plans to remove the above two hooks since resctrl self has needed
information via the rdt_resource::alloc_capable and rdt_resource::mon_capable flags.

For reference:
	https://lore.kernel.org/lkml/20260916231320.14502-7-tony.luck@intel.com/

I see this has impact on this driver that I comment more below.

...

> diff --git a/drivers/resctrl/cbqri_resctrl.c b/drivers/resctrl/cbqri_resctrl.c
> new file mode 100644
> index 000000000000..0c4bfa2a7f43
> --- /dev/null
> +++ b/drivers/resctrl/cbqri_resctrl.c
> @@ -0,0 +1,785 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
> +
> +#include <linux/bitfield.h>
> +#include <linux/cacheinfo.h>
> +#include <linux/cleanup.h>
> +#include <linux/riscv_cbqri.h>

Just an observation (I have no intention to comment on the style):
The new c files in this series seem to make an effort to have the #include
files organized alphabetically, except when if comes to the file above?

> +#include <linux/cpu.h>
> +#include <linux/cpufeature.h>
> +#include <linux/cpuhotplug.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/rculist.h>
> +#include <linux/resctrl.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +
> +#include <asm/csr.h>
> +#include <asm/qos.h>
> +
> +#include "cbqri_internal.h"
> +
> +struct cbqri_resctrl_res {
> +	struct cbqri_controller *ctrl;
> +	struct rdt_resource     resctrl_res;
> +	bool                    cdp_enabled;
> +};
> +
> +struct cbqri_resctrl_dom {
> +	struct rdt_ctrl_domain  resctrl_ctrl_dom;
> +	struct cbqri_controller *hw_ctrl;
> +};

Is cbqri_resctrl_dom::hw_ctrl necessary? From what I can tell it is
initialized from cbqri_resctrl_res::ctrl when a new domain is created
and thus identical in all domains that belong to a resource. 

It looks to me as though the resource is always available when the associated
controller information is needed so it looks like just cbqri_resctrl_res::ctrl
could do?

The way the data is organized results in potentially confusing code since, for
example, when initializing the control values of a single domain
(cbqri_init_domain_ctrlval()) the RCID count is obtained from the domain's
cbqri_resctrl_dom::hw_ctrl::rcid_count but when initializing the control values of
all domains (resctrl_arch_reset_all_ctrls()) the RCID count is obtained from the
resource's cbqri_resctrl_res::ctrl::rcid_count instead of each domain's domain
cbqri_resctrl_dom::hw_ctrl::rcid_count.

> +
> +static struct cbqri_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES];
> +
> +static bool exposed_alloc_capable;
> +
> +/* Protects ctrl_domain list mutations across CPU hotplug. */
> +static DEFINE_MUTEX(cbqri_domain_list_lock);
> +
> +static struct rdt_ctrl_domain *
> +cbqri_find_ctrl_domain(struct list_head *h, int id)
> +{
> +	struct rdt_domain_hdr *hdr = resctrl_find_domain(h, id, NULL);
> +
> +	return hdr ? container_of(hdr, struct rdt_ctrl_domain, hdr) : NULL;
> +}
> +

...

> +
> +bool resctrl_arch_alloc_capable(void)
> +{
> +	return exposed_alloc_capable;
> +}
> +

...

> +
> +static void cbqri_resctrl_accumulate_caps(void)
> +{
> +	int rid;
> +
> +	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
> +		struct cbqri_resctrl_res *hw_res = &cbqri_resctrl_resources[rid];
> +
> +		if (!hw_res->ctrl)
> +			continue;
> +		if (hw_res->ctrl->alloc_capable)
> +			exposed_alloc_capable = true;
> +	}
> +}

Since it captures whether any of the resources are alloc_capable it looks like
exposed_alloc_capable indeed reflects the same information as what resctrl will
use after resctrl_arch_alloc_capable() is dropped (see patch linked earlier).
Except that cbqri_resctrl_teardown() only resets exposed_alloc_capable but not
the rdt_resource::mon_capable and rdt_resource::alloc_capable flags that the new
helper will use to determine if a resource is capable of allocation or monitoring.

The new helper will thus change behavior. It looks like resctrl_exit() is only
called on error path during initialization so it seems unlikely that those flags
will be referenced by this driver.

If there are plans to call resctrl_exit() in other paths like MPAM driver does there
may be issues since the resctrl filesystem may still be mounted and when user space
unmounts it the rdt_resource::mon_capable and rdt_resource::alloc_capable will be
used and result in some arch callbacks called.

I wonder if it may simplify driver initialization to call resctrl_init() _after_
setting up the CPU online/offline handlers (this is how the x86 driver does it).

> +
> +/*
> + * Create, list-insert, and online a fresh ctrl_domain backing ctrl on
> + * resource res, seeded with cpu and identified by dom_id. Caller must
> + * hold cbqri_domain_list_lock and must have already verified that no
> + * existing ctrl_domain on res carries this id.
> + */
> +static struct rdt_ctrl_domain *cbqri_create_ctrl_domain(struct cbqri_controller *ctrl,
> +							struct rdt_resource *res,
> +							unsigned int cpu, int dom_id)
> +{
> +	struct rdt_ctrl_domain *domain;
> +	struct list_head *pos = NULL;
> +	int err;
> +
> +	domain = cbqri_new_domain(ctrl);
> +	if (!domain)
> +		return ERR_PTR(-ENOMEM);
> +
> +	cpumask_set_cpu(cpu, &domain->hdr.cpu_mask);
> +	domain->hdr.id = dom_id;
> +	domain->hdr.type = RESCTRL_CTRL_DOMAIN;
> +	domain->hdr.rid = res->rid;
> +
> +	err = cbqri_init_domain_ctrlval(res, domain);
> +	if (err)
> +		goto free;
> +
> +	err = resctrl_online_ctrl_domain(res, domain);
> +	if (err)
> +		goto free;
> +
> +	/*
> +	 * Publish only after the domain is fully initialized and online, so a
> +	 * reader walking the RCU list never sees a half-built domain.
> +	 */
> +	resctrl_find_domain(&res->ctrl_domains, dom_id, &pos);

The caller loops over the domain list to determine whether it needs to create
a new domain or not and then this domain create code loops over the list again
to determine where to insert the new domain. Could this perhaps be simplified if
the first loop  cbqri_attach_cpu_to_all_ctrls()->cbqri_find_ctrl_domain() determines
the position at the same time as determining the presence and pass that to
this function to just do the insert without searching the list again?

> +	list_add_tail_rcu(&domain->hdr.list, pos);
> +
> +	return domain;
> +free:
> +	kfree(container_of(domain, struct cbqri_resctrl_dom, resctrl_ctrl_dom));
> +	return ERR_PTR(err);
> +}

...

> +/*
> + * Attach a CPU to the capacity controller at each cache level whose cache
> + * the CPU shares. On failure, detach the CPU from everything attached so
> + * far: the cpuhp core does not run this state's offline teardown when its
> + * startup fails, so a partial attach would otherwise leak into the domain
> + * cpu_masks. Caller holds cbqri_domain_list_lock.
> + */
> +static int cbqri_attach_cpu_to_all_ctrls(unsigned int cpu)
> +{
> +	static const u32 levels[] = { 2, 3 };
> +	struct cbqri_controller *ctrl, *c;
> +	struct cbqri_resctrl_res *hw_res;
> +	struct rdt_ctrl_domain *d;
> +	struct cacheinfo *ci;
> +	int i, rid;
> +
> +	lockdep_assert_held(&cbqri_domain_list_lock);
> +
> +	/*
> +	 * Hold cbqri_controllers_lock across the walk so a controller
> +	 * registered after boot cannot corrupt it. The register path takes
> +	 * it as a leaf and never cbqri_domain_list_lock, so this nesting
> +	 * cannot invert.
> +	 */
> +	guard(mutex)(&cbqri_controllers_lock);
> +
> +	for (i = 0; i < ARRAY_SIZE(levels); i++) {
> +		ci = get_cpu_cacheinfo_level(cpu, levels[i]);
> +		if (!ci)
> +			continue;
> +
> +		rid = cbqri_cache_level_to_rid(levels[i]);
> +		hw_res = &cbqri_resctrl_resources[rid];
> +		if (!hw_res->ctrl)
> +			continue;
> +
> +		/* The controller backing this CPU's cache at this level. */
> +		ctrl = NULL;
> +		list_for_each_entry(c, &cbqri_controllers, list) {
> +			if (c->type == CBQRI_CONTROLLER_TYPE_CAPACITY &&> +			    c->alloc_capable &&
> +			    c->cache.cache_level == levels[i] &&
> +			    c->cache.cache_id == ci->id) {
> +				ctrl = c;
> +				break;

Is it necessary to loop over cbqri_controllers and repeat these tests? Above seems to
duplicate the work done during initialization (cbqri_resctrl_pick_caches()) that resulted
in initialization of cbqri_resctrl_res::ctrl so it seems that after testing for existence
this function could just use cbqri_resctrl_res::ctrl without again referencing cbqri_controllers?

If I understand correctly it may be that new controllers appear in cbqri_controllers 
after this driver is initialized and the resources are initialized so the CPU online/offline
helpers may need to take care how any controllers in cbqri_controllers not seen by
cbqri_resctrl_setup() are handled.

> +			}
> +		}
> +		if (!ctrl)
> +			continue;
> +
> +		d = cbqri_find_ctrl_domain(&hw_res->resctrl_res.ctrl_domains,
> +					   ci->id);
> +		if (d) {
> +			cpumask_set_cpu(cpu, &d->hdr.cpu_mask);
> +			continue;
> +		}
> +
> +		d = cbqri_create_ctrl_domain(ctrl, &hw_res->resctrl_res, cpu,
> +					     ci->id);
> +		if (IS_ERR(d)) {
> +			cbqri_detach_cpu_from_all_ctrls(cpu);
> +			return PTR_ERR(d);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static bool cbqri_resctrl_inited;
> +
> +static void cbqri_resctrl_teardown(void)
> +{
> +	int rid;
> +
> +	if (!cbqri_resctrl_inited)
> +		return;
> +
> +	resctrl_exit();
> +
> +	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
> +		struct cbqri_resctrl_res *hw_res = &cbqri_resctrl_resources[rid];
> +
> +		hw_res->ctrl = NULL;
> +		hw_res->cdp_enabled = false;
> +	}
> +	exposed_alloc_capable = false;
> +	cbqri_resctrl_inited = false;
> +}
> +
> +static int cbqri_resctrl_setup(void)
> +{
> +	int rid;
> +	int err;
> +
> +	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++)
> +		cbqri_resctrl_resources[rid].resctrl_res.rid = rid;
> +
> +	cbqri_resctrl_pick_caches();
> +
> +	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++)
> +		cbqri_resctrl_control_init(&cbqri_resctrl_resources[rid]);
> +
> +	cbqri_resctrl_accumulate_caps();
> +
> +	if (!exposed_alloc_capable) {
> +		pr_debug("no resctrl-capable CBQRI controllers found\n");
> +		return -ENODEV;
> +	}
> +
> +	err = resctrl_init();
> +	if (err)
> +		return err;
> +
> +	cbqri_resctrl_inited = true;
> +	return 0;
> +}
> +
> +static int cbqri_resctrl_online_cpu(unsigned int cpu)
> +{
> +	int err;
> +
> +	mutex_lock(&cbqri_domain_list_lock);
> +	err = cbqri_attach_cpu_to_all_ctrls(cpu);
> +	mutex_unlock(&cbqri_domain_list_lock);
> +	if (err)
> +		return err;
> +
> +	/*
> +	 * Seed the per-CPU default RCID/MCID to the reserved (0, 0) pair and
> +	 * notify the resctrl core so it tracks this CPU in the default group.
> +	 */
> +	resctrl_arch_set_cpu_default_closid_rmid(cpu, 0, 0);
> +	resctrl_online_cpu(cpu);
> +	return 0;
> +}
> +
> +static int cbqri_resctrl_offline_cpu(unsigned int cpu)
> +{
> +	resctrl_offline_cpu(cpu);
> +
> +	mutex_lock(&cbqri_domain_list_lock);
> +	cbqri_detach_cpu_from_all_ctrls(cpu);
> +	mutex_unlock(&cbqri_domain_list_lock);
> +	return 0;
> +}
> +
> +static int __init cbqri_arch_late_init(void)
> +{
> +	int err;
> +
> +	if (!riscv_isa_extension_available(NULL, SSQOSID))
> +		return -ENODEV;
> +
> +	err = cbqri_resctrl_setup();
> +	if (err)
> +		return err;
> +
> +	err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "cbqri:online",
> +				cbqri_resctrl_online_cpu,
> +				cbqri_resctrl_offline_cpu);
> +	if (err < 0) {
> +		cbqri_resctrl_teardown();

cbqri_resctrl_teardown() calls resctrl_exit() that will complain
via WARN_ON_ONCE() if any domains exist at that time. It is not clear
to me if this can be guaranteed here.

> +		return err;
> +	}
> +
> +	return 0;
> +}
> +late_initcall(cbqri_arch_late_init);
> 

Reinette

  parent reply	other threads:[~2026-09-18  0:54 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-17 16:39 [PATCH v8 0/5] riscv: Add initial CBQRI resctrl support Drew Fustini
2026-09-17 16:39 ` [PATCH v8 1/5] riscv_cbqri: Add capacity controller probe and allocation device ops Drew Fustini
2026-09-17 16:39 ` [PATCH v8 2/5] riscv_cbqri: resctrl: Add cache allocation via capacity block mask Drew Fustini
2026-09-17 16:57   ` sashiko-bot
2026-09-17 19:59     ` Drew Fustini
2026-09-18  0:54   ` Reinette Chatre [this message]
2026-09-17 16:39 ` [PATCH v8 3/5] riscv_cbqri: Make RESCTRL_FS available on RISC-V Drew Fustini
2026-09-17 16:39 ` [PATCH v8 4/5] dt-bindings: riscv: Add binding for CBQRI controllers Drew Fustini
2026-09-17 16:39 ` [PATCH v8 5/5] riscv_cbqri: Add CBQRI capacity allocation platform driver Drew Fustini
2026-09-17 17:11   ` sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=fb4813cf-b21e-43ca-9bd4-4b42d2214aa6@intel.com \
    --to=reinette.chatre@intel.com \
    --cc=Dave.Martin@arm.com \
    --cc=alex@ghiti.fr \
    --cc=aou@eecs.berkeley.edu \
    --cc=aricciardi@baylibre.com \
    --cc=atish.patra@linux.dev \
    --cc=atishp@rivosinc.com \
    --cc=babu.moger@amd.com \
    --cc=ben.horgan@arm.com \
    --cc=bigeasy@linutronix.de \
    --cc=bp@alien8.de \
    --cc=clrkwllms@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=conor.dooley@microchip.com \
    --cc=cp0613@linux.alibaba.com \
    --cc=cuiyunhui@bytedance.com \
    --cc=dave.hansen@linux.intel.com \
    --cc=devicetree@vger.kernel.org \
    --cc=fenghuay@nvidia.com \
    --cc=fustini@kernel.org \
    --cc=gong.shuai@sanechips.com.cn \
    --cc=gsh517@gmail.com \
    --cc=guo.wenjia23@zte.com.cn \
    --cc=james.morse@arm.com \
    --cc=krzk+dt@kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=linux-rt-devel@lists.linux.dev \
    --cc=liu.qingtao2@zte.com.cn \
    --cc=liwei1518@gmail.com \
    --cc=mindal@semihalf.com \
    --cc=palmer@dabbelt.com \
    --cc=peternewman@google.com \
    --cc=pjw@kernel.org \
    --cc=rkrcmar@ventanamicro.com \
    --cc=robh@kernel.org \
    --cc=rostedt@goodmis.org \
    --cc=samuel.holland@sifive.com \
    --cc=tony.luck@intel.com \
    --cc=vasu@rivosinc.com \
    --cc=ved@rivosinc.com \
    --cc=x86@kernel.org \
    --cc=zhangzhanpeng.jasper@bytedance.com \
    --cc=zhiwei_liu@linux.alibaba.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®