summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sched/ext/ext.c35
-rw-r--r--kernel/sched/ext/internal.h16
2 files changed, 41 insertions, 10 deletions
diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
index e11c66bd23e7..aca8d2380509 100644
--- a/kernel/sched/ext/ext.c
+++ b/kernel/sched/ext/ext.c
@@ -5144,6 +5144,7 @@ static const char *scx_cap_names[__SCX_NR_CAPS] = {
[__SCX_CAP_ENQ_IMMED] = "enq_immed",
[__SCX_CAP_ENQ] = "enq",
[__SCX_CAP_PREEMPT] = "preempt",
+ [__SCX_CAP_PERF] = "perf",
};
static ssize_t scx_attr_caps_show(struct kobject *kobj,
@@ -9786,6 +9787,7 @@ static s32 scx_cpuperf_set(struct scx_sched *sch, s32 cpu, u32 perf)
{
struct rq *rq, *locked_rq;
struct rq_flags rf;
+ s32 ret;
if (unlikely(perf > SCX_CPUPERF_ONE)) {
scx_error(sch, "Invalid cpuperf target %u for CPU %d", perf, cpu);
@@ -9816,13 +9818,24 @@ static s32 scx_cpuperf_set(struct scx_sched *sch, s32 cpu, u32 perf)
update_rq_clock(rq);
}
- rq->scx.cpuperf_target = perf;
- cpufreq_update_util(rq, 0);
+ /*
+ * ecaps updates are folded under the rq lock, making this test
+ * authoritative: a write can never land after a revoke has taken
+ * effect on @cpu.
+ */
+ if (likely(!scx_missing_caps(sch, cpu, SCX_CAP_PERF))) {
+ rq->scx.cpuperf_target = perf;
+ cpufreq_update_util(rq, 0);
+ ret = 0;
+ } else {
+ __scx_add_event(sch, SCX_EV_SUB_CIDPERF_DENIED, 1);
+ ret = -EACCES;
+ }
if (!locked_rq)
rq_unlock_irqrestore(rq, &rf);
- return 0;
+ return ret;
}
/**
@@ -9859,10 +9872,13 @@ __bpf_kfunc void scx_bpf_cpuperf_set(s32 cpu, u32 perf, const struct bpf_prog_au
* @perf: target performance level [0, %SCX_CPUPERF_ONE]
* @aux: implicit BPF argument to access bpf_prog_aux hidden from BPF progs
*
- * cid-addressed equivalent of scx_bpf_cpuperf_set().
+ * cid-addressed equivalent of scx_bpf_cpuperf_set(). A sub-sched needs
+ * SCX_CAP_PERF on @cid. Returns 0 if the target was applied, -%EACCES if
+ * the write was denied for missing caps, other -errnos if @cid didn't
+ * resolve.
*/
-__bpf_kfunc void scx_bpf_cidperf_set(s32 cid, u32 perf,
- const struct bpf_prog_aux *aux)
+__bpf_kfunc s32 scx_bpf_cidperf_set(s32 cid, u32 perf,
+ const struct bpf_prog_aux *aux)
{
struct scx_sched *sch;
s32 cpu;
@@ -9871,11 +9887,12 @@ __bpf_kfunc void scx_bpf_cidperf_set(s32 cid, u32 perf,
sch = scx_prog_sched(aux);
if (unlikely(!sch))
- return;
+ return -ENODEV;
cpu = scx_cid_to_cpu(sch, cid);
if (cpu < 0)
- return;
- scx_bpf_cpuperf_set(cpu, perf, aux);
+ return cpu;
+
+ return scx_cpuperf_set(sch, cpu, perf);
}
/**
diff --git a/kernel/sched/ext/internal.h b/kernel/sched/ext/internal.h
index 308d16320818..886f1d132e6b 100644
--- a/kernel/sched/ext/internal.h
+++ b/kernel/sched/ext/internal.h
@@ -1206,6 +1206,12 @@ struct scx_event_stats {
* sub-sched lacked baseline access on the target cid.
*/
s64 SCX_EV_SUB_REENQ_DENIED;
+
+ /*
+ * The number of times scx_bpf_cidperf_set() was denied because the
+ * sub-sched lacked SCX_CAP_PERF on the target cid.
+ */
+ s64 SCX_EV_SUB_CIDPERF_DENIED;
};
#define SCX_EVENTS_LIST(SCX_EVENT) \
@@ -1227,7 +1233,8 @@ struct scx_event_stats {
SCX_EVENT(SCX_EV_SUB_FORCED_ADMIT); \
SCX_EVENT(SCX_EV_SUB_PREEMPT_DENIED); \
SCX_EVENT(SCX_EV_SUB_KICK_DENIED); \
- SCX_EVENT(SCX_EV_SUB_REENQ_DENIED)
+ SCX_EVENT(SCX_EV_SUB_REENQ_DENIED); \
+ SCX_EVENT(SCX_EV_SUB_CIDPERF_DENIED)
struct scx_sched;
@@ -1353,6 +1360,11 @@ struct scx_sched_pnode {
* - SCX_ENQ_PREEMPT inserts
* - SCX_KICK_PREEMPT kicks
*
+ * PERF control the cid's cpu power/perf management state, currently the
+ * cpufreq target set through scx_bpf_cidperf_set(). Hardware
+ * control is a separate axis from queue access: PERF neither
+ * implies nor is implied by the caps above.
+ *
* Implied caps apply to the holder's own use of a cid, not to delegation.
* scx_bpf_sub_grant() delegates literally-held caps, so a cap held only through
* implication is usable but cannot be re-delegated to a child. When granting a
@@ -1363,6 +1375,7 @@ enum scx_cap_flags {
__SCX_CAP_ENQ_IMMED = 0,
__SCX_CAP_ENQ = 1,
__SCX_CAP_PREEMPT = 2,
+ __SCX_CAP_PERF = 3,
__SCX_NR_CAPS,
__SCX_CAP_ALL = BIT_U64(__SCX_NR_CAPS) - 1,
@@ -1370,6 +1383,7 @@ enum scx_cap_flags {
SCX_CAP_ENQ_IMMED = BIT_U64(__SCX_CAP_ENQ_IMMED),
SCX_CAP_ENQ = BIT_U64(__SCX_CAP_ENQ),
SCX_CAP_PREEMPT = BIT_U64(__SCX_CAP_PREEMPT),
+ SCX_CAP_PERF = BIT_U64(__SCX_CAP_PERF),
/* alias for minimal cap to make any use of a cpu */
SCX_CAP_BASE = SCX_CAP_ENQ_IMMED,