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