1*326ba66dSDrew Fustini /* SPDX-License-Identifier: GPL-2.0 */
2*326ba66dSDrew Fustini #ifndef _ASM_RISCV_QOS_H
3*326ba66dSDrew Fustini #define _ASM_RISCV_QOS_H
4*326ba66dSDrew Fustini
5*326ba66dSDrew Fustini #include <linux/percpu-defs.h>
6*326ba66dSDrew Fustini
7*326ba66dSDrew Fustini #ifdef CONFIG_RISCV_ISA_SSQOSID
8*326ba66dSDrew Fustini
9*326ba66dSDrew Fustini #include <linux/bitfield.h>
10*326ba66dSDrew Fustini #include <linux/cpufeature.h>
11*326ba66dSDrew Fustini #include <linux/sched.h>
12*326ba66dSDrew Fustini
13*326ba66dSDrew Fustini #include <asm/csr.h>
14*326ba66dSDrew Fustini #include <asm/hwcap.h>
15*326ba66dSDrew Fustini
16*326ba66dSDrew Fustini /* cached value of srmcfg csr for each cpu */
17*326ba66dSDrew Fustini DECLARE_PER_CPU(u32, cpu_srmcfg);
18*326ba66dSDrew Fustini
19*326ba66dSDrew Fustini /* default srmcfg value for each cpu, set via resctrl cpu assignment */
20*326ba66dSDrew Fustini DECLARE_PER_CPU(u32, cpu_srmcfg_default);
21*326ba66dSDrew Fustini
__switch_to_srmcfg(struct task_struct * next)22*326ba66dSDrew Fustini static inline void __switch_to_srmcfg(struct task_struct *next)
23*326ba66dSDrew Fustini {
24*326ba66dSDrew Fustini u32 thread_srmcfg, default_srmcfg;
25*326ba66dSDrew Fustini
26*326ba66dSDrew Fustini thread_srmcfg = READ_ONCE(next->thread.srmcfg);
27*326ba66dSDrew Fustini default_srmcfg = __this_cpu_read(cpu_srmcfg_default);
28*326ba66dSDrew Fustini
29*326ba66dSDrew Fustini /*
30*326ba66dSDrew Fustini * RCID and MCID inherit from cpu_srmcfg_default independently.
31*326ba66dSDrew Fustini * RESCTRL_RESERVED_CLOSID and RESCTRL_RESERVED_RMID are both 0, so a
32*326ba66dSDrew Fustini * zero field means "unassigned" and takes the CPU default.
33*326ba66dSDrew Fustini */
34*326ba66dSDrew Fustini if (thread_srmcfg == 0) {
35*326ba66dSDrew Fustini thread_srmcfg = default_srmcfg;
36*326ba66dSDrew Fustini } else {
37*326ba66dSDrew Fustini u32 rcid = FIELD_GET(SRMCFG_RCID_MASK, thread_srmcfg);
38*326ba66dSDrew Fustini u32 mcid = FIELD_GET(SRMCFG_MCID_MASK, thread_srmcfg);
39*326ba66dSDrew Fustini
40*326ba66dSDrew Fustini if (rcid == 0 || mcid == 0) {
41*326ba66dSDrew Fustini if (rcid == 0)
42*326ba66dSDrew Fustini rcid = FIELD_GET(SRMCFG_RCID_MASK, default_srmcfg);
43*326ba66dSDrew Fustini if (mcid == 0)
44*326ba66dSDrew Fustini mcid = FIELD_GET(SRMCFG_MCID_MASK, default_srmcfg);
45*326ba66dSDrew Fustini thread_srmcfg = FIELD_PREP(SRMCFG_RCID_MASK, rcid) |
46*326ba66dSDrew Fustini FIELD_PREP(SRMCFG_MCID_MASK, mcid);
47*326ba66dSDrew Fustini }
48*326ba66dSDrew Fustini }
49*326ba66dSDrew Fustini
50*326ba66dSDrew Fustini if (thread_srmcfg != __this_cpu_read(cpu_srmcfg)) {
51*326ba66dSDrew Fustini /*
52*326ba66dSDrew Fustini * No fence around the csrw. Ssqosid is silent on srmcfg
53*326ba66dSDrew Fustini * ordering versus memory accesses, so a few accesses at the
54*326ba66dSDrew Fustini * switch boundary may carry the previous RCID/MCID. The
55*326ba66dSDrew Fustini * tagging inaccuracy is bounded and acceptable for QoS.
56*326ba66dSDrew Fustini */
57*326ba66dSDrew Fustini __this_cpu_write(cpu_srmcfg, thread_srmcfg);
58*326ba66dSDrew Fustini csr_write(CSR_SRMCFG, thread_srmcfg);
59*326ba66dSDrew Fustini }
60*326ba66dSDrew Fustini }
61*326ba66dSDrew Fustini
has_srmcfg(void)62*326ba66dSDrew Fustini static __always_inline bool has_srmcfg(void)
63*326ba66dSDrew Fustini {
64*326ba66dSDrew Fustini return riscv_has_extension_unlikely(RISCV_ISA_EXT_SSQOSID);
65*326ba66dSDrew Fustini }
66*326ba66dSDrew Fustini
67*326ba66dSDrew Fustini #else /* ! CONFIG_RISCV_ISA_SSQOSID */
68*326ba66dSDrew Fustini
69*326ba66dSDrew Fustini struct task_struct;
has_srmcfg(void)70*326ba66dSDrew Fustini static __always_inline bool has_srmcfg(void) { return false; }
__switch_to_srmcfg(struct task_struct * next)71*326ba66dSDrew Fustini static inline void __switch_to_srmcfg(struct task_struct *next) { }
72*326ba66dSDrew Fustini
73*326ba66dSDrew Fustini #endif /* CONFIG_RISCV_ISA_SSQOSID */
74*326ba66dSDrew Fustini #endif /* _ASM_RISCV_QOS_H */
75