xref: /linux/arch/riscv/include/asm/qos.h (revision 073e62fd33fe9cec754cb89e60c0ebbab781a50a)
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