@@ -409,6 +409,25 @@ config RISCV_ISA_C
If you don't know what to do here, say Y.
+config RISCV_ISA_SSQOSID
+ bool "Ssqosid extension support for supervisor mode QoS ID"
+ default y
+ help
+ Adds support for the Ssqosid ISA extension (Supervisor-mode
+ Quality of Service ID).
+
+ Ssqosid defines the sqoscfg CSR which allows the system to tag
+ the running process with RCID (Resource Control ID) and MCID
+ (Monitoring Counter ID). The RCID is used determine resource
+ allocation. The MCID is used to track resource usage in event
+ counters.
+
+ For example, a cache controller may use the RCID to apply a
+ cache partitioning scheme and use the MCID to track how much
+ cache a process, or a group of processes, is using.
+
+ If you don't know what to do here, say Y.
+
config RISCV_ISA_SVNAPOT
bool "Svnapot extension support for supervisor mode NAPOT pages"
depends on 64BIT && MMU
@@ -59,6 +59,13 @@
#define SATP_ASID_MASK _AC(0xFFFF, UL)
#endif
+/* SQOSCFG fields */
+#define SQOSCFG_RCID_MASK _AC(0x00000FFF, UL)
+#define SQOSCFG_MCID_MASK SQOSCFG_RCID_MASK
+#define SQOSCFG_MCID_SHIFT 16
+#define SQOSCFG_MASK ((SQOSCFG_MCID_MASK << SQOSCFG_MCID_SHIFT) | \
+ SQOSCFG_RCID_MASK)
+
/* Exception cause high bit - is an interrupt if set */
#define CAUSE_IRQ_FLAG (_AC(1, UL) << (__riscv_xlen - 1))
@@ -245,6 +252,7 @@
#define CSR_STVAL 0x143
#define CSR_SIP 0x144
#define CSR_SATP 0x180
+#define CSR_SQOSCFG 0x181
#define CSR_STIMECMP 0x14D
#define CSR_STIMECMPH 0x15D
@@ -39,6 +39,9 @@ struct thread_struct {
unsigned long s[12]; /* s[0]: frame pointer */
struct __riscv_d_ext_state fstate;
unsigned long bad_cause;
+#ifdef CONFIG_RISCV_ISA_SSQOSID
+ u32 sqoscfg;
+#endif
};
/* Whitelist the fstate from the task_struct for hardened usercopy */
new file mode 100644
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_RISCV_QOS_H
+#define _ASM_RISCV_QOS_H
+
+#ifdef CONFIG_RISCV_ISA_SSQOSID
+
+#include <linux/sched.h>
+#include <linux/jump_label.h>
+
+#include <asm/barrier.h>
+#include <asm/csr.h>
+#include <asm/hwcap.h>
+
+/* cached value of sqoscfg csr for each cpu */
+DECLARE_PER_CPU(u32, cpu_sqoscfg);
+
+static inline void __switch_to_sqoscfg(struct task_struct *prev,
+ struct task_struct *next)
+{
+ u32 *cpu_sqoscfg_ptr = this_cpu_ptr(&cpu_sqoscfg);
+ u32 thread_sqoscfg;
+
+ thread_sqoscfg = READ_ONCE(next->thread.sqoscfg);
+
+ if (thread_sqoscfg != *cpu_sqoscfg_ptr) {
+ *cpu_sqoscfg_ptr = thread_sqoscfg;
+ csr_write(CSR_SQOSCFG, thread_sqoscfg);
+ }
+}
+
+static __always_inline bool has_sqoscfg(void)
+{
+ return riscv_has_extension_likely(RISCV_ISA_EXT_SSQOSID);
+}
+
+#else /* ! CONFIG_RISCV_ISA_SSQOSID */
+
+static __always_inline bool has_sqoscfg(void) { return false; }
+#define __switch_to_sqoscfg(__prev, __next) do { } while (0)
+
+#endif /* CONFIG_RISCV_ISA_SSQOSID */
+
+#endif /* _ASM_RISCV_QOS_H */
@@ -12,6 +12,7 @@
#include <asm/processor.h>
#include <asm/ptrace.h>
#include <asm/csr.h>
+#include <asm/qos.h>
#ifdef CONFIG_FPU
extern void __fstate_save(struct task_struct *save_to);
@@ -78,6 +79,8 @@ do { \
struct task_struct *__next = (next); \
if (has_fpu()) \
__switch_to_aux(__prev, __next); \
+ if (has_sqoscfg()) \
+ __switch_to_sqoscfg(__prev, __next); \
((last) = __switch_to(__prev, __next)); \
} while (0)
@@ -89,3 +89,4 @@ obj-$(CONFIG_COMPAT) += compat_signal.o
obj-$(CONFIG_COMPAT) += compat_vdso/
obj-$(CONFIG_64BIT) += pi/
+obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos/
new file mode 100644
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos.o
new file mode 100644
@@ -0,0 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <asm/qos.h>
+
+/* cached value of sqoscfg csr for each cpu */
+DEFINE_PER_CPU(u32, cpu_sqoscfg);