[PATCH v9 5/5] riscv_cbqri: Add CBQRI capacity allocation platform driver

Sunil V L sunilvl at oss.qualcomm.com
Mon Oct 12 10:03:21 PDT 2026


On Sat, Oct 3, 2026 at 12:45 PM Drew Fustini <fustini at kernel.org> wrote:
>
> Add a platform driver for CBQRI capacity controllers described in
> device tree with the riscv,cbqri-capacity-controller compatible.
>
> The controller node points at the cache it governs with a
> riscv,cbqri-cache phandle. The driver looks that cache up in cacheinfo
> and uses its cache id as the resctrl domain id, so the binding does not
> need to carry a CPU mask. The controller is then handed to the CBQRI
> core, which probes its capabilities and decides whether to expose it
> through resctrl.
>
> Nothing is vendor-specific and reg is the CBQRI register block itself,
> so any SoC that describes a CBQRI capacity controller in device tree can
> use the driver unchanged.
>
> Assisted-by: LLM
> Tested-by: Chen Pei <cp0613 at linux.alibaba.com>
> Signed-off-by: Drew Fustini <fustini at kernel.org>
> ---
>  MAINTAINERS                      |   1 +
>  drivers/resctrl/Kconfig          |  15 +++++
>  drivers/resctrl/Makefile         |   1 +
>  drivers/resctrl/cbqri_capacity.c | 127 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 144 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c362d53ed355..00b92842ef12 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -23573,6 +23573,7 @@ F:      Documentation/devicetree/bindings/riscv/riscv,cbqri.yaml
>  F:     arch/riscv/include/asm/qos.h
>  F:     arch/riscv/include/asm/resctrl.h
>  F:     arch/riscv/kernel/qos.c
> +F:     drivers/resctrl/cbqri_capacity.c
>  F:     drivers/resctrl/cbqri_devices.c
>  F:     drivers/resctrl/cbqri_internal.h
>  F:     drivers/resctrl/cbqri_resctrl.c
> diff --git a/drivers/resctrl/Kconfig b/drivers/resctrl/Kconfig
> index 617b813b9808..689a91873d7b 100644
> --- a/drivers/resctrl/Kconfig
> +++ b/drivers/resctrl/Kconfig
> @@ -41,6 +41,21 @@ menuconfig RISCV_CBQRI
>           allocation through the resctrl filesystem at /sys/fs/resctrl when
>           RESCTRL_FS is also enabled.
>
> +if RISCV_CBQRI
> +
> +config RISCV_CBQRI_CAPACITY
> +       bool "RISC-V CBQRI cache capacity-allocation controller"
> +       depends on OF
> +       help
> +         Enable driver for a RISC-V CBQRI capacity controller that
> +         governs a CPU cache, matching the "riscv,cbqri-capacity-controller"
> +         compatible. The controller's cache phandle gives the cache level and
> +         id, which the driver registers as a resctrl cache-allocation resource.
> +
> +         Say N unless your device tree describes a CBQRI capacity controller.
> +
> +endif
> +
>  config RISCV_CBQRI_RESCTRL_FS
>         bool
>         default y if RISCV_CBQRI && RESCTRL_FS
> diff --git a/drivers/resctrl/Makefile b/drivers/resctrl/Makefile
> index a7631712dba9..c8339113ef1f 100644
> --- a/drivers/resctrl/Makefile
> +++ b/drivers/resctrl/Makefile
> @@ -7,3 +7,4 @@ ccflags-$(CONFIG_ARM64_MPAM_DRIVER_DEBUG)       += -DDEBUG
>  obj-$(CONFIG_RISCV_CBQRI)                      += cbqri.o
>  cbqri-y                                                += cbqri_devices.o
>  cbqri-$(CONFIG_RISCV_CBQRI_RESCTRL_FS)         += cbqri_resctrl.o
> +cbqri-$(CONFIG_RISCV_CBQRI_CAPACITY)           += cbqri_capacity.o
> diff --git a/drivers/resctrl/cbqri_capacity.c b/drivers/resctrl/cbqri_capacity.c
> new file mode 100644
> index 000000000000..0670a676bdb1
> --- /dev/null
> +++ b/drivers/resctrl/cbqri_capacity.c
> @@ -0,0 +1,127 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Platform driver for a RISC-V CBQRI capacity controller that backs a CPU
> + * cache. The controller is described in device tree by the generic
> + * "riscv,cbqri-capacity-controller" compatible together with a phandle to the
> + * cache node it governs. The driver hands it to the CBQRI core, which probes
> + * the capabilities register and exposes a controller that supports allocation
> + * as the resctrl cache allocation resource for that cache.
> + */
> +
> +#define pr_fmt(fmt) "cbqri-capacity: " fmt
> +
> +#include <linux/cacheinfo.h>
> +#include <linux/cpu.h>
> +#include <linux/device-id/of.h>
> +#include <linux/ioport.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/printk.h>
> +#include <linux/riscv_cbqri.h>
> +#include <linux/types.h>
> +
> +static int cbqri_capacity_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct cbqri_controller_info info = {};
> +       struct device_node *cache_np;
> +       struct resource *res;
> +       u32 rcid_count, cache_level;
> +       int cache_id, cpu, ret;
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (!res)
> +               return -EINVAL;
> +
Unless I am missing something, I think you can simplify the code by
using devm_platform_ioremap_resource().

> +       ret = of_property_read_u32(dev->of_node, "riscv,cbqri-rcid", &rcid_count);
> +       if (ret) {
> +               dev_err(dev, "missing riscv,cbqri-rcid\n");
> +               return ret;
> +       }
> +
> +       cache_np = of_parse_phandle(dev->of_node, "riscv,cbqri-cache", 0);
> +       if (!cache_np) {
> +               dev_err(dev, "missing riscv,cbqri-cache phandle\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = of_property_read_u32(cache_np, "cache-level", &cache_level);
> +       if (ret) {
> +               dev_err(dev, "%pOF: missing cache-level\n", cache_np);
> +               goto out_put;
> +       }
> +
> +       /*
> +        * Associate the controller with its cache instance via cacheinfo.
> +        * The matching cache provides the cache id used as the resctrl
> +        * domain id.
> +        *
> +        * Taking the first leaf at the level is sufficient, because fw_token
> +        * is keyed on the DT cache node, so sibling leaves of a split cache
> +        * share it, and riscv,cbqri-cache must reference a unified shared
> +        * cache (cache-unified), not a split private L1.
> +        */
> +       cache_id = -1;
> +       cpus_read_lock();
> +       for_each_online_cpu(cpu) {
> +               struct cacheinfo *ci = get_cpu_cacheinfo_level(cpu, cache_level);
> +
> +               if (ci && ci->fw_token == cache_np) {
> +                       cache_id = ci->id;
> +                       break;
> +               }
> +       }
> +       cpus_read_unlock();
> +
> +       if (cache_id < 0) {
> +               dev_err(dev, "%pOF: no online hart reports an L%u cache for this node\n",
> +                       cache_np, cache_level);
> +               ret = -ENODEV;
> +               goto out_put;
> +       }
> +
> +       info.type = CBQRI_CONTROLLER_TYPE_CAPACITY;
> +       info.addr = res->start;
> +       info.size = resource_size(res);
> +       info.rcid_count = rcid_count;
> +       info.cache_id = cache_id;
> +
> +       ret = riscv_cbqri_register_cc_dt(&info, cache_level);
>
As I mentioned in the comment for another patch, this function doesn't
need to have "_dt" in its name.

Thanks,
Sunil



More information about the linux-riscv mailing list