[PATCH RFC v3 10/11] ACPI: RISC-V: Parse RISC-V Quality of Service Controller (RQSC) table
Drew Fustini <[email protected]>
| Newsgroups | dev.linux.lists.acpica-devel,org.infradead.lists.linux-riscv,org.kernel.vger.linux-acpi,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Add parser for the ACPI RQSC table which describes the capacity and bandwidth QoS controllers in a system. For each table entry, allocate a cbqri_controller struct and populate it with the controller type, MMIO base address, RCID/MCID counts, and resource identifiers (cache ID for capacity controllers, proximity domain for bandwidth controllers). Cache controller cpumasks are resolved via acpi_pptt_get_cpumask_from_cache_id(). Bandwidth controller cpumasks are derived from the proximity domain's NUMA node. Controllers with invalid addresses or failed cpumask lookups are skipped with a warning. The populated controller list is consumed by qos_resctrl_setup() in arch/riscv/kernel/qos/ to probe the hardware and register resctrl domains. 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 <[email protected]> --- MAINTAINERS | 1 + arch/riscv/include/asm/acpi.h | 10 ++++ drivers/acpi/riscv/Makefile | 1 + drivers/acpi/riscv/rqsc.c | 136 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index af9698a16439..d5ec7d29bf11 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22786,6 +22786,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 DRIVERS diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h index 6e13695120bc..62296a2a519b 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 __init 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..d7ae8729987a 100644 --- a/drivers/acpi/riscv/Makefile +++ b/drivers/acpi/riscv/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += rhct.o init.o irq.o +obj-$(CONFIG_RISCV_ISA_SSQOSID) += rqsc.o obj-$(CONFIG_ACPI_PROCESSOR_IDLE) += cpuidle.o obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o obj-$(CONFIG_ACPI_RIMT) += rimt.o diff --git a/drivers/acpi/riscv/rqsc.c b/drivers/acpi/riscv/rqsc.c new file mode 100644 index 000000000000..f647051be0bf --- /dev/null +++ b/drivers/acpi/riscv/rqsc.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 Tenstorrent + * Author: Drew Fustini <[email protected]> + */ + +#define pr_fmt(fmt) "ACPI: RQSC: " fmt + +#include <linux/acpi.h> +#include <linux/bits.h> +#include <linux/riscv_qos.h> + +#define CBQRI_CTRL_SIZE 0x1000 + +int __init acpi_parse_rqsc(struct acpi_table_header *table) +{ + struct acpi_table_rqsc *rqsc; + struct acpi_table_rqsc_fields *end; + struct acpi_table_rqsc_fields *node; + int err; + int num_controllers = 0; + + rqsc = (struct acpi_table_rqsc *)table; + + end = ACPI_ADD_PTR(struct acpi_table_rqsc_fields, rqsc, rqsc->header.length); + + for (node = ACPI_ADD_PTR(struct acpi_table_rqsc_fields, rqsc, + sizeof(struct acpi_table_rqsc)); + node < end; + node = ACPI_ADD_PTR(struct acpi_table_rqsc_fields, node, node->length) + ) { + struct cbqri_controller *ctrl; + + if (node->length < sizeof(*node)) { + pr_err("malformed RQSC entry: length %u < %zu, aborting\n", + node->length, sizeof(*node)); + err = -EINVAL; + goto err_free_controllers; + } + + ctrl = kzalloc_obj(*ctrl, GFP_KERNEL); + if (!ctrl) { + err = -ENOMEM; + goto err_free_controllers; + } + + ctrl->type = node->type; + /* reg[1] is the MMIO base address per the RQSC table layout */ + ctrl->addr = node->reg[1]; + ctrl->size = CBQRI_CTRL_SIZE; + ctrl->rcid_count = node->rcid; + ctrl->mcid_count = node->mcid; + + if (!ctrl->addr) { + pr_warn("skipping controller with invalid addr=0x0\n"); + kfree(ctrl); + continue; + } + + if (node->nres == 0) { + pr_warn("controller at %pa has no resource descriptors, skipping\n", + &ctrl->addr); + kfree(ctrl); + continue; + } + + if (node->length < sizeof(*node) + sizeof(node->res[0])) { + pr_warn("controller at %pa: node too short for resource descriptor, skipping\n", + &ctrl->addr); + kfree(ctrl); + continue; + } + + if (node->nres > 1) + pr_warn("controller at %pa has %u resource descriptors, using first\n", + &ctrl->addr, node->nres); + + pr_debug("Found controller with type %u addr %pa size %pa rcid %u mcid %u\n", + ctrl->type, &ctrl->addr, &ctrl->size, + ctrl->rcid_count, ctrl->mcid_count); + if (ctrl->type == CBQRI_CONTROLLER_TYPE_CAPACITY) { + ctrl->cache.cache_id = (u32)node->res[0].id1; + ctrl->cache.cache_level = + find_acpi_cache_level_from_id(ctrl->cache.cache_id); + + if (acpi_pptt_get_cache_size_from_id(ctrl->cache.cache_id, + &ctrl->cache.cache_size)) { + pr_warn("failed to determine size for cache id 0x%x\n", + ctrl->cache.cache_id); + ctrl->cache.cache_size = 0; + } + + pr_debug("Cache controller has ID 0x%x level %u size %u\n", + ctrl->cache.cache_id, ctrl->cache.cache_level, + ctrl->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 = acpi_pptt_get_cpumask_from_cache_id(ctrl->cache.cache_id, + &ctrl->cache.cpu_mask); + if (err) { + pr_warn("Failed to get cpumask for cache id 0x%x (%d), skipping\n", + ctrl->cache.cache_id, err); + kfree(ctrl); + continue; + } + + } else if (ctrl->type == CBQRI_CONTROLLER_TYPE_BANDWIDTH) { + ctrl->mem.prox_dom = (u32)node->res[0].id1; + cpumask_copy(&ctrl->mem.cpu_mask, + cpumask_of_node(pxm_to_node(ctrl->mem.prox_dom))); + pr_debug("Memory controller with proximity domain %u\n", + ctrl->mem.prox_dom); + } + + /* List shared with RISC-V QoS resctrl implementation */ + list_add_tail(&ctrl->list, &cbqri_controllers); + num_controllers++; + } + + pr_info("found %d CBQRI controllers\n", num_controllers); + return 0; + +err_free_controllers: + while (!list_empty(&cbqri_controllers)) { + struct cbqri_controller *ctrl; + + ctrl = list_first_entry(&cbqri_controllers, struct cbqri_controller, list); + list_del(&ctrl->list); + kfree(ctrl); + } + return err; +} -- 2.43.0