bpf: Add uclamp helper

Introduce a new bpf helper function, bpf_set_current_uclamp(), which
wraps sched_setattr() and allows a bpf program to specify the minimum
and maximum utilisation values for its task context.

Signed-off-by: Will Deacon <will@kernel.org>
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index fe8aab4..7aac488 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -5528,6 +5528,15 @@ union bpf_attr {
  *	Return
  *		The capacity of *cpu* or 0 if *cpu* does not correspond to a
  *		valid CPU.
+ *
+ * int bpf_set_current_uclamp(u32 sched_util_min, u32 sched_util_max)
+ *	Description
+ *		Set the uclamp utilization constaints for the current task.
+ *		Note that this differs slightly from the sched_setattr(2)
+ *		interface in that a util value of -1 is ignored rather
+ *		than resetting to the system default.
+ *	Return
+ *		0 on success, negative error code otherwise.
  */
 #define ___BPF_FUNC_MAPPER(FN, ctx...)			\
 	FN(unspec, 0, ##ctx)				\
@@ -5745,6 +5754,7 @@ union bpf_attr {
 	FN(get_cpu_freq, 212, ##ctx)			\
 	FN(get_cpu_hw_max_freq, 213, ##ctx)		\
 	FN(get_cpu_scale, 214, ##ctx)			\
+	FN(set_current_uclamp, 215, ##ctx)		\
 	/* */
 
 /* backwards-compatibility macros for users of __BPF_FUNC_MAPPER that don't
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 1e4e4a3..d346cb1 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -24,6 +24,8 @@
 #include <linux/btf_ids.h>
 #include <linux/bpf_mem_alloc.h>
 
+#include <uapi/linux/sched/types.h>
+
 #include "../../lib/kstrtox.h"
 
 /* If kernel subsystem is allowing eBPF programs to call this function,
@@ -481,6 +483,28 @@ const struct bpf_func_proto bpf_get_cpu_scale_proto = {
 	.ret_type	= RET_INTEGER,
 	.arg1_type	= ARG_ANYTHING,
 };
+
+BPF_CALL_2(bpf_set_current_uclamp, u32, sched_util_min, u32, sched_util_max)
+{
+	u32 uc_flags = (sched_util_min != -1 ? SCHED_FLAG_UTIL_CLAMP_MIN : 0) |
+		       (sched_util_max != -1 ? SCHED_FLAG_UTIL_CLAMP_MAX : 0) ;
+	struct sched_attr attr = {
+		.sched_policy	= -1 /* SETPARAM_POLICY */,
+		.sched_flags	= uc_flags | SCHED_FLAG_KEEP_ALL,
+		.sched_util_min	= sched_util_min,
+		.sched_util_max	= sched_util_max,
+	};
+
+	return sched_setattr(current, &attr);
+}
+
+const struct bpf_func_proto bpf_set_current_uclamp_proto = {
+	.func		= bpf_set_current_uclamp,
+	.gpl_only	= false,
+	.ret_type	= RET_INTEGER,
+	.arg1_type	= ARG_ANYTHING,
+	.arg2_type	= ARG_ANYTHING,
+};
 #endif /* CONFIG_CPU_FREQ */
 
 #define BPF_STRTOX_BASE_MASK 0x1F
@@ -1750,6 +1774,8 @@ bpf_base_func_proto(enum bpf_func_id func_id)
 		return &bpf_get_cpu_hw_max_freq_proto;
 	case BPF_FUNC_get_cpu_scale:
 		return &bpf_get_cpu_scale_proto;
+	case BPF_FUNC_set_current_uclamp:
+		return &bpf_set_current_uclamp_proto;
 #endif
 	default:
 		break;