Re: [External] [PATCH RFC v2 16/17] acpi: riscv: Parse RISC-V Quality of Service Controller (RQSC) table
From: yunhui cui <hidden>
Date: 2026-02-02 11:09:01
Also in:
linux-acpi, linux-riscv, lkml
Hi Drew, On Thu, Jan 29, 2026 at 4:28 AM Drew Fustini [off-list ref] wrote:
quoted hunk ↗ jump to hunk
Add driver to parse the ACPI RISC-V Quality of Service Controller (RQSC) table which describes the capacity and bandwidth QoS controllers in a system. The QoS controllers implement the RISC-V Capacity and Bandwidth Controller QoS Register Interface (CBQRI) specification. Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0 Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/ Signed-off-by: Drew Fustini <fustini@kernel.org> --- MAINTAINERS | 1 + arch/riscv/include/asm/acpi.h | 10 ++++ drivers/acpi/riscv/Makefile | 2 +- drivers/acpi/riscv/rqsc.c | 112 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 1 deletion(-)diff --git a/MAINTAINERS b/MAINTAINERS index 96ead357a634..e96a83dc9a02 100644 --- a/MAINTAINERS +++ b/MAINTAINERS@@ -22512,6 +22512,7 @@ S: Supported F: arch/riscv/include/asm/qos.h F: arch/riscv/include/asm/resctrl.h F: arch/riscv/kernel/qos/ +F: drivers/acpi/riscv/rqsc.c F: include/linux/riscv_qos.h RISC-V RPMI AND MPXY DRIVERSdiff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h index 6e13695120bc..16c6e25eed1e 100644 --- a/arch/riscv/include/asm/acpi.h +++ b/arch/riscv/include/asm/acpi.h@@ -71,6 +71,16 @@ int acpi_get_riscv_isa(struct acpi_table_header *table, void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size, u32 *cboz_size, u32 *cbop_size); + +#ifdef CONFIG_RISCV_ISA_SSQOSID +int acpi_parse_rqsc(struct acpi_table_header *table); +#else +static inline int acpi_parse_rqsc(struct acpi_table_header *table) +{ + return -EINVAL; +} +#endif /* CONFIG_RISCV_ISA_SSQOSID */ + #else static inline void acpi_init_rintc_map(void) { } static inline struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu)diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile index 1284a076fa88..cf0f38c93a9f 100644 --- a/drivers/acpi/riscv/Makefile +++ b/drivers/acpi/riscv/Makefile@@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y += rhct.o init.o irq.o +obj-y += rhct.o rqsc.o init.o irq.o obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o obj-$(CONFIG_ACPI_RIMT) += rimt.odiff --git a/drivers/acpi/riscv/rqsc.c b/drivers/acpi/riscv/rqsc.c new file mode 100644 index 000000000000..a86ddb39fae4 --- /dev/null +++ b/drivers/acpi/riscv/rqsc.c@@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 Tenstorrent + * Author: Drew Fustini <fustini@kernel.org> + * + */ + +#define pr_fmt(fmt) "ACPI: RQSC: " fmt + +#include <linux/acpi.h> +#include <linux/bits.h> +#include <linux/riscv_qos.h> + +#ifdef CONFIG_RISCV_ISA_SSQOSID + +#define CBQRI_CTRL_SIZE 0x1000 + +static struct acpi_table_rqsc *acpi_get_rqsc(void) +{ + static struct acpi_table_header *rqsc; + acpi_status status; + + /* + * RQSC will be used at runtime on every CPU, so we + * don't need to call acpi_put_table() to release the table mapping. + */ + if (!rqsc) { + status = acpi_get_table(ACPI_SIG_RQSC, 0, &rqsc); + if (ACPI_FAILURE(status)) { + pr_warn_once("No RQSC table found\n"); + return NULL; + } + } + + return (struct acpi_table_rqsc *)rqsc; +} + +int acpi_parse_rqsc(struct acpi_table_header *table) +{ + struct acpi_table_rqsc *rqsc; + int err; + + BUG_ON(acpi_disabled); + if (!table) { + rqsc = acpi_get_rqsc(); + if (!rqsc) + return -ENOENT; + } else { + rqsc = (struct acpi_table_rqsc *)table; + } + + for (int i = 0; i < rqsc->num; i++) { + struct cbqri_controller_info *ctrl_info; + + ctrl_info = kzalloc(sizeof(*ctrl_info), GFP_KERNEL); + if (!ctrl_info) + return -ENOMEM; + + ctrl_info->type = rqsc->f[i].type; + ctrl_info->addr = rqsc->f[i].reg[1]; + ctrl_info->size = CBQRI_CTRL_SIZE; + ctrl_info->rcid_count = rqsc->f[i].rcid; + ctrl_info->mcid_count = rqsc->f[i].mcid; + + pr_info("Found controller with type %u addr 0x%lx size %lu rcid %u mcid %u", + ctrl_info->type, ctrl_info->addr, ctrl_info->size, + ctrl_info->rcid_count, ctrl_info->mcid_count); + + if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_CAPACITY) { + ctrl_info->cache.cache_id = rqsc->f[i].res.id1; + ctrl_info->cache.cache_level = + find_acpi_cache_level_from_id(ctrl_info->cache.cache_id); + + struct acpi_pptt_cache *cache; + + cache = find_acpi_cache_from_id(ctrl_info->cache.cache_id); + if (cache) { + ctrl_info->cache.cache_size = cache->size; + } else { + pr_warn("%s(): failed to determine size for cache id 0x%x", + __func__, ctrl_info->cache.cache_id); + ctrl_info->cache.cache_size = 0; + } + + pr_info("Cache controller has ID 0x%x level %u size %u ", + ctrl_info->cache.cache_id, ctrl_info->cache.cache_level, + ctrl_info->cache.cache_size); + + /* + * For CBQRI, any cpu (technically a hart in RISC-V terms) + * can access the memory-mapped registers of any CBQRI + * controller in the system. + */ + err = cpumask_parse("FF", &ctrl_info->cache.cpu_mask);
Hardcode? acpi_pptt_get_cpumask_from_cache_id(ctrl_info->cache.cache_id, &ctrl_info->cache.cpu_mask); ?
+ if (err)
+ pr_err("Failed to convert cores mask string to cpumask (%d)", err);
+
+ } else if (ctrl_info->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) {
+ ctrl_info->mem.prox_dom = rqsc->f[i].res.id1;
+ pr_info("Memory controller with proximity domain %u",
+ ctrl_info->mem.prox_dom);
+ }
+
+ /* Fill the list shared with RISC-V QoS resctrl */
+ INIT_LIST_HEAD(&ctrl_info->list);
+ list_add_tail(&ctrl_info->list, &cbqri_controllers);
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_RISCV_ISA_SSQOSID */
--
2.43.0Thanks, Yunhui