/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _ASM_RISCV_QOS_H #define _ASM_RISCV_QOS_H #include #ifdef CONFIG_RISCV_ISA_SSQOSID #include #include #include #include #include /* 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, default_srmcfg; thread_srmcfg = READ_ONCE(next->thread.srmcfg); default_srmcfg = __this_cpu_read(cpu_srmcfg_default); /* * RCID and MCID inherit from cpu_srmcfg_default independently. * RESCTRL_RESERVED_CLOSID and RESCTRL_RESERVED_RMID are both 0, so a * zero field means "unassigned" and takes the CPU default. */ if (thread_srmcfg == 0) { thread_srmcfg = default_srmcfg; } else { u32 rcid = FIELD_GET(SRMCFG_RCID_MASK, thread_srmcfg); u32 mcid = FIELD_GET(SRMCFG_MCID_MASK, thread_srmcfg); if (rcid == 0 || mcid == 0) { if (rcid == 0) rcid = FIELD_GET(SRMCFG_RCID_MASK, default_srmcfg); if (mcid == 0) mcid = FIELD_GET(SRMCFG_MCID_MASK, default_srmcfg); thread_srmcfg = FIELD_PREP(SRMCFG_RCID_MASK, rcid) | FIELD_PREP(SRMCFG_MCID_MASK, mcid); } } if (thread_srmcfg != __this_cpu_read(cpu_srmcfg)) { /* * No fence around the csrw. Ssqosid is silent on srmcfg * ordering versus memory accesses, so a few accesses at the * switch boundary may carry the previous RCID/MCID. The * tagging inaccuracy is bounded and acceptable for QoS. */ __this_cpu_write(cpu_srmcfg, thread_srmcfg); csr_write(CSR_SRMCFG, thread_srmcfg); } } 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 */