[PATCH RFC v4 03/18] riscv: add support for srmcfg CSR from Ssqosid extension
Drew Fustini <[email protected]> Sun, 10 May 2026 22:10:59 -0700
| Newsgroups | dev.linux.lists.acpica-devel,dev.linux.lists.linux-rt-devel,org.infradead.lists.linux-riscv,org.kernel.vger.linux-acpi,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Add support for the srmcfg CSR defined in the Ssqosid ISA extension. The CSR contains two fields: - Resource Control ID (RCID) for resource allocation - Monitoring Counter ID (MCID) for tracking resource usage Requests from a hart to shared resources are tagged with these IDs, allowing resource usage to be associated with the running task. Add a srmcfg field to thread_struct with the same format as the CSR so the scheduler can set the RCID and MCID for each task on context switch. A per-cpu cpu_srmcfg variable mirrors the CSR state to avoid redundant writes. L1D-hot memory access is faster than a CSR read and avoids traps under virtualization. A per-cpu cpu_srmcfg_default holds the default srmcfg for each CPU as set by resctrl CPU group assignment. On context switch, if the next task belongs to the default resource group (srmcfg == 0), the CPU's default value is used instead. This implements resctrl allocation rule 2: default-group tasks on a CPU assigned to a specific group receive that group's allocations. Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0 Assisted-by: Claude:claude-opus-4-7 Co-developed-by: Kornel Dulęba <[email protected]> Signed-off-by: Kornel Dulęba <[email protected]> Signed-off-by: Drew Fustini <[email protected]> --- MAINTAINERS | 8 +++++ arch/riscv/Kconfig | 18 +++++++++++ arch/riscv/include/asm/csr.h | 5 +++ arch/riscv/include/asm/processor.h | 3 ++ arch/riscv/include/asm/qos.h | 64 ++++++++++++++++++++++++++++++++++++++ arch/riscv/include/asm/switch_to.h | 3 ++ arch/riscv/kernel/Makefile | 2 ++ arch/riscv/kernel/qos.c | 49 +++++++++++++++++++++++++++++ 8 files changed, 152 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4d1e198959e4..5039f48f387a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23006,6 +23006,14 @@ F: drivers/perf/riscv_pmu.c F: drivers/perf/riscv_pmu_legacy.c F: drivers/perf/riscv_pmu_sbi.c +RISC-V QOS RESCTRL SUPPORT +M: Drew Fustini <[email protected]> +R: yunhui cui <[email protected]> +L: [email protected] +S: Supported +F: arch/riscv/include/asm/qos.h +F: arch/riscv/kernel/qos.c + RISC-V RPMI AND MPXY DRIVERS M: Rahul Pathak <[email protected]> M: Anup Patel <[email protected]> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index d235396c4514..a7e87c49be21 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -591,6 +591,24 @@ config RISCV_ISA_SVNAPOT If you don't know what to do here, say Y. +config RISCV_ISA_SSQOSID + bool "Ssqosid extension support for supervisor mode Quality of Service ID" + depends on 64BIT + default n + help + Adds support for the Ssqosid ISA extension (Supervisor-mode + Quality of Service ID). + + Ssqosid defines the srmcfg CSR which allows the system to tag the + running process with an RCID (Resource Control ID) and MCID + (Monitoring Counter ID). The RCID is used to determine resource + allocation. The MCID is used to track resource usage in event + counters. + + For example, a cache controller may use the RCID to apply a + cache partitioning scheme and use the MCID to track how much + cache a process, or a group of processes, is using. + config RISCV_ISA_SVPBMT bool "Svpbmt extension support for supervisor mode page-based memory types" depends on 64BIT && MMU diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 31b8988f4488..7bce928e5daa 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -84,6 +84,10 @@ #define SATP_ASID_MASK _AC(0xFFFF, UL) #endif +/* SRMCFG fields */ +#define SRMCFG_RCID_MASK GENMASK(11, 0) +#define SRMCFG_MCID_MASK GENMASK(27, 16) + /* Exception cause high bit - is an interrupt if set */ #define CAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1)) @@ -328,6 +332,7 @@ #define CSR_STVAL 0x143 #define CSR_SIP 0x144 #define CSR_SATP 0x180 +#define CSR_SRMCFG 0x181 #define CSR_STIMECMP 0x14D #define CSR_STIMECMPH 0x15D diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 812517b2cec1..49a386d74cd3 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -123,6 +123,9 @@ struct thread_struct { /* A forced icache flush is not needed if migrating to the previous cpu. */ unsigned int prev_cpu; #endif +#ifdef CONFIG_RISCV_ISA_SSQOSID + u32 srmcfg; +#endif }; /* Whitelist the fstate from the task_struct for hardened usercopy */ diff --git a/arch/riscv/include/asm/qos.h b/arch/riscv/include/asm/qos.h new file mode 100644 index 000000000000..6988fe37551e --- /dev/null +++ b/arch/riscv/include/asm/qos.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_RISCV_QOS_H +#define _ASM_RISCV_QOS_H + +#include <linux/percpu-defs.h> + +#ifdef CONFIG_RISCV_ISA_SSQOSID + +#include <linux/cpufeature.h> +#include <linux/sched.h> + +#include <asm/csr.h> +#include <asm/fence.h> +#include <asm/hwcap.h> + +/* cached value of srmcfg csr for each cpu */ +DECLARE_PER_CPU(u32, cpu_srmcfg); + +/* default srmcfg value for each cpu, set via resctrl cpu assignment */ +DECLARE_PER_CPU(u32, cpu_srmcfg_default); + +static inline void __switch_to_srmcfg(struct task_struct *next) +{ + u32 thread_srmcfg; + + thread_srmcfg = READ_ONCE(next->thread.srmcfg); + + /* Default-group tasks (thread.srmcfg == 0) follow this CPU's default. */ + if (thread_srmcfg == 0) + thread_srmcfg = __this_cpu_read(cpu_srmcfg_default); + + if (thread_srmcfg != __this_cpu_read(cpu_srmcfg)) { + /* + * Drain stores from the outgoing task before the CSR write + * so they retain the previous RCID/MCID tag at the cache + * interconnect. + */ + RISCV_FENCE(rw, o); + + __this_cpu_write(cpu_srmcfg, thread_srmcfg); + csr_write(CSR_SRMCFG, thread_srmcfg); + /* + * Order the csrw before the new task's loads/stores so they + * pick up the new tag. Zicsr 6.1.1 makes CSR writes weakly + * ordered (device-output) vs memory ops. Ssqosid v1.0 is + * silent so honor the general CSR rule. + */ + RISCV_FENCE(o, rw); + } +} + +static __always_inline bool has_srmcfg(void) +{ + return riscv_has_extension_unlikely(RISCV_ISA_EXT_SSQOSID); +} + +#else /* ! CONFIG_RISCV_ISA_SSQOSID */ + +struct task_struct; +static __always_inline bool has_srmcfg(void) { return false; } +static inline void __switch_to_srmcfg(struct task_struct *next) { } + +#endif /* CONFIG_RISCV_ISA_SSQOSID */ +#endif /* _ASM_RISCV_QOS_H */ diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index 0e71eb82f920..1c7ea53ec012 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -14,6 +14,7 @@ #include <asm/processor.h> #include <asm/ptrace.h> #include <asm/csr.h> +#include <asm/qos.h> #ifdef CONFIG_FPU extern void __fstate_save(struct task_struct *save_to); @@ -119,6 +120,8 @@ do { \ __switch_to_fpu(__prev, __next); \ if (has_vector() || has_xtheadvector()) \ __switch_to_vector(__prev, __next); \ + if (has_srmcfg()) \ + __switch_to_srmcfg(__next); \ if (switch_to_should_flush_icache(__next)) \ local_flush_icache_all(); \ __switch_to_envcfg(__next); \ diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index cabb99cadfb6..ebe1c3588177 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -128,3 +128,5 @@ obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += bugs.o obj-$(CONFIG_RISCV_USER_CFI) += usercfi.o + +obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos.o diff --git a/arch/riscv/kernel/qos.c b/arch/riscv/kernel/qos.c new file mode 100644 index 000000000000..75bda2ed89e1 --- /dev/null +++ b/arch/riscv/kernel/qos.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <linux/cpu.h> +#include <linux/cpuhotplug.h> +#include <linux/percpu-defs.h> +#include <linux/types.h> + +#include <asm/cpufeature-macros.h> +#include <asm/hwcap.h> +#include <asm/qos.h> + +/* cached value of srmcfg csr for each cpu */ +DEFINE_PER_CPU(u32, cpu_srmcfg); + +/* default srmcfg value for each cpu, set via resctrl cpu assignment */ +DEFINE_PER_CPU(u32, cpu_srmcfg_default); + +/* + * Seed the per-CPU srmcfg cache to a sentinel that no real srmcfg encoding + * can produce (MCID << 16 | RCID, both fields well under 16 bits) so the + * next __switch_to_srmcfg() unconditionally writes the CSR. Ssqosid v1.0 + * leaves CSR state across hart stop/start implementation-defined, so the + * cached value cannot be trusted after online. + */ +static int riscv_srmcfg_online(unsigned int cpu) +{ + per_cpu(cpu_srmcfg, cpu) = U32_MAX; + return 0; +} + +static int __init riscv_srmcfg_init(void) +{ + unsigned int cpu; + int err; + + if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SSQOSID)) + return 0; + + /* Seed already-online CPUs. The cpuhp callback covers later onlines. */ + for_each_online_cpu(cpu) + per_cpu(cpu_srmcfg, cpu) = U32_MAX; + + err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "riscv/srmcfg:online", + riscv_srmcfg_online, NULL); + if (err < 0) + pr_warn("srmcfg cpuhp registration failed (%d), cpus brought online after boot will not invalidate the CSR_SRMCFG cache\n", + err); + return err; +} +arch_initcall(riscv_srmcfg_init); -- 2.43.0