mirror of
https://github.com/torvalds/linux.git
synced 2026-10-16 21:00:02 +02:00
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. The context-switch path writes the field to the CSR, and resctrl_arch_set_closid_rmid() updates it when a task is assigned to a resctrl control or monitoring group. A per-cpu cpu_srmcfg_default holds the default srmcfg for each CPU, set by resctrl_arch_set_cpu_default_closid_rmid() on CPU group assignment. On context switch, RCID and MCID inherit from the CPU default independently: a task whose thread RCID field is zero takes the CPU default's RCID, and likewise for MCID. 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. Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0 Assisted-by: Claude:claude-opus-4-7 Co-developed-by: Kornel Dulęba <mindal@semihalf.com> Signed-off-by: Kornel Dulęba <mindal@semihalf.com> Signed-off-by: Drew Fustini <fustini@kernel.org> Link: https://patch.msgid.link/20260729-dfustini-atl-sc-cbqri-dt-v6-3-7c22b05d461b@kernel.org Signed-off-by: Paul Walmsley <pjw@kernel.org>
102 lines
3.4 KiB
C
102 lines
3.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
#include <linux/cpu.h>
|
|
#include <linux/cpu_pm.h>
|
|
#include <linux/cpuhotplug.h>
|
|
#include <linux/notifier.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. Seeded to U32_MAX so the next
|
|
* __switch_to_srmcfg() unconditionally writes the CSR. The encoding
|
|
* MCID << 16 | RCID with both fields well under 16 bits can never
|
|
* produce this sentinel. This covers early-boot context switches that
|
|
* happen before riscv_srmcfg_init() runs as an arch_initcall.
|
|
*/
|
|
DEFINE_PER_CPU(u32, cpu_srmcfg) = U32_MAX;
|
|
|
|
/* default srmcfg value for each cpu, set via resctrl cpu assignment */
|
|
DEFINE_PER_CPU(u32, cpu_srmcfg_default);
|
|
|
|
/*
|
|
* Invalidate the per-CPU srmcfg cache. Used as both the cpuhp startup
|
|
* and teardown callback. U32_MAX is not a valid srmcfg value
|
|
* (MCID << 16 | RCID, both fields under 16 bits), so the next
|
|
* __switch_to_srmcfg() always writes the CSR.
|
|
*
|
|
* Ssqosid leaves the CSR implementation-defined across hart stop/start,
|
|
* so the cached value cannot be trusted after online. The startup
|
|
* callback runs at CPUHP_AP_ONLINE_DYN, before CPUHP_AP_ACTIVE makes
|
|
* the CPU schedulable, so the cache is invalidated before any normal
|
|
* task runs and the CSR is written on that task's first switch.
|
|
* The teardown callback is not relied on. Idle and per-CPU kthreads keep
|
|
* switching as the CPU goes down and overwrite the sentinel with the CPU
|
|
* default, so it does not survive the offline period.
|
|
*/
|
|
static int riscv_srmcfg_reset_cache(unsigned int cpu)
|
|
{
|
|
per_cpu(cpu_srmcfg, cpu) = U32_MAX;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* CPU PM notifier: invalidate the cached srmcfg on resume from a deep
|
|
* idle / suspend. Ssqosid leaves CSR_SRMCFG state across low-power
|
|
* transitions implementation-defined, and the boot CPU never goes
|
|
* through the cpuhp online callback during system suspend, so without
|
|
* this hook __switch_to_srmcfg() would skip the CSR write when the
|
|
* outgoing task happens to share its srmcfg with the pre-suspend cache.
|
|
*/
|
|
static int riscv_srmcfg_pm_notify(struct notifier_block *nb,
|
|
unsigned long action, void *unused)
|
|
{
|
|
switch (action) {
|
|
case CPU_PM_EXIT:
|
|
case CPU_PM_ENTER_FAILED:
|
|
/*
|
|
* The CSR is implementation-defined across the low-power
|
|
* transition. Invalidate the cache and eagerly rewrite the
|
|
* CSR for the current task so it does not run mis-tagged
|
|
* until the next context switch.
|
|
*/
|
|
__this_cpu_write(cpu_srmcfg, U32_MAX);
|
|
__switch_to_srmcfg(current);
|
|
break;
|
|
}
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
static struct notifier_block riscv_srmcfg_pm_nb = {
|
|
.notifier_call = riscv_srmcfg_pm_notify,
|
|
};
|
|
|
|
static int __init riscv_srmcfg_init(void)
|
|
{
|
|
int err;
|
|
|
|
if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SSQOSID))
|
|
return 0;
|
|
|
|
/*
|
|
* cpuhp_setup_state() invokes the startup callback locally on every
|
|
* already-online CPU, so no separate seed loop is needed here.
|
|
*/
|
|
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "riscv/srmcfg:online",
|
|
riscv_srmcfg_reset_cache, riscv_srmcfg_reset_cache);
|
|
if (err < 0)
|
|
pr_warn("srmcfg: cpuhp setup failed (%d), cache not invalidated on CPU online\n",
|
|
err);
|
|
|
|
/*
|
|
* Register the PM notifier even if the cpuhp setup failed. It is
|
|
* independent of the cpuhp state and guards suspend/resume.
|
|
*/
|
|
cpu_pm_register_notifier(&riscv_srmcfg_pm_nb);
|
|
return 0;
|
|
}
|
|
arch_initcall(riscv_srmcfg_init);
|