···26422642 return ret;26432643}2644264426452645+static void process_ddsp_deferred_locals(struct rq *rq)26462646+{26472647+ struct task_struct *p;26482648+26492649+ lockdep_assert_rq_held(rq);26502650+26512651+ /*26522652+ * Now that @rq can be unlocked, execute the deferred enqueueing of26532653+ * tasks directly dispatched to the local DSQs of other CPUs. See26542654+ * direct_dispatch(). Keep popping from the head instead of using26552655+ * list_for_each_entry_safe() as dispatch_local_dsq() may unlock @rq26562656+ * temporarily.26572657+ */26582658+ while ((p = list_first_entry_or_null(&rq->scx.ddsp_deferred_locals,26592659+ struct task_struct, scx.dsq_list.node))) {26602660+ s32 ret;26612661+26622662+ list_del_init(&p->scx.dsq_list.node);26632663+26642664+ ret = dispatch_to_local_dsq(rq, p->scx.ddsp_dsq_id, p,26652665+ p->scx.ddsp_enq_flags);26662666+ WARN_ON_ONCE(ret == DTL_NOT_LOCAL);26672667+ }26682668+}26692669+26452670static void set_next_task_scx(struct rq *rq, struct task_struct *p, bool first)26462671{26472672 if (p->scx.flags & SCX_TASK_QUEUED) {···27092684 }27102685}2711268627122712-static void process_ddsp_deferred_locals(struct rq *rq)26872687+static enum scx_cpu_preempt_reason26882688+preempt_reason_from_class(const struct sched_class *class)27132689{27142714- struct task_struct *p;26902690+#ifdef CONFIG_SMP26912691+ if (class == &stop_sched_class)26922692+ return SCX_CPU_PREEMPT_STOP;26932693+#endif26942694+ if (class == &dl_sched_class)26952695+ return SCX_CPU_PREEMPT_DL;26962696+ if (class == &rt_sched_class)26972697+ return SCX_CPU_PREEMPT_RT;26982698+ return SCX_CPU_PREEMPT_UNKNOWN;26992699+}2715270027162716- lockdep_assert_rq_held(rq);27012701+static void switch_class_scx(struct rq *rq, struct task_struct *next)27022702+{27032703+ const struct sched_class *next_class = next->sched_class;27042704+27052705+ if (!scx_enabled())27062706+ return;27072707+#ifdef CONFIG_SMP27082708+ /*27092709+ * Pairs with the smp_load_acquire() issued by a CPU in27102710+ * kick_cpus_irq_workfn() who is waiting for this CPU to perform a27112711+ * resched.27122712+ */27132713+ smp_store_release(&rq->scx.pnt_seq, rq->scx.pnt_seq + 1);27142714+#endif27152715+ if (!static_branch_unlikely(&scx_ops_cpu_preempt))27162716+ return;2717271727182718 /*27192719- * Now that @rq can be unlocked, execute the deferred enqueueing of27202720- * tasks directly dispatched to the local DSQs of other CPUs. See27212721- * direct_dispatch(). Keep popping from the head instead of using27222722- * list_for_each_entry_safe() as dispatch_local_dsq() may unlock @rq27232723- * temporarily.27192719+ * The callback is conceptually meant to convey that the CPU is no27202720+ * longer under the control of SCX. Therefore, don't invoke the callback27212721+ * if the next class is below SCX (in which case the BPF scheduler has27222722+ * actively decided not to schedule any tasks on the CPU).27242723 */27252725- while ((p = list_first_entry_or_null(&rq->scx.ddsp_deferred_locals,27262726- struct task_struct, scx.dsq_list.node))) {27272727- s32 ret;27242724+ if (sched_class_above(&ext_sched_class, next_class))27252725+ return;2728272627292729- list_del_init(&p->scx.dsq_list.node);27272727+ /*27282728+ * At this point we know that SCX was preempted by a higher priority27292729+ * sched_class, so invoke the ->cpu_release() callback if we have not27302730+ * done so already. We only send the callback once between SCX being27312731+ * preempted, and it regaining control of the CPU.27322732+ *27332733+ * ->cpu_release() complements ->cpu_acquire(), which is emitted the27342734+ * next time that balance_scx() is invoked.27352735+ */27362736+ if (!rq->scx.cpu_released) {27372737+ if (SCX_HAS_OP(cpu_release)) {27382738+ struct scx_cpu_release_args args = {27392739+ .reason = preempt_reason_from_class(next_class),27402740+ .task = next,27412741+ };2730274227312731- ret = dispatch_to_local_dsq(rq, p->scx.ddsp_dsq_id, p,27322732- p->scx.ddsp_enq_flags);27332733- WARN_ON_ONCE(ret == DTL_NOT_LOCAL);27432743+ SCX_CALL_OP(SCX_KF_CPU_RELEASE,27442744+ cpu_release, cpu_of(rq), &args);27452745+ }27462746+ rq->scx.cpu_released = true;27342747 }27352748}27362749···28832820 return time_after64(a->scx.core_sched_at, b->scx.core_sched_at);28842821}28852822#endif /* CONFIG_SCHED_CORE */28862886-28872887-static enum scx_cpu_preempt_reason28882888-preempt_reason_from_class(const struct sched_class *class)28892889-{28902890-#ifdef CONFIG_SMP28912891- if (class == &stop_sched_class)28922892- return SCX_CPU_PREEMPT_STOP;28932893-#endif28942894- if (class == &dl_sched_class)28952895- return SCX_CPU_PREEMPT_DL;28962896- if (class == &rt_sched_class)28972897- return SCX_CPU_PREEMPT_RT;28982898- return SCX_CPU_PREEMPT_UNKNOWN;28992899-}29002900-29012901-static void switch_class_scx(struct rq *rq, struct task_struct *next)29022902-{29032903- const struct sched_class *next_class = next->sched_class;29042904-29052905- if (!scx_enabled())29062906- return;29072907-#ifdef CONFIG_SMP29082908- /*29092909- * Pairs with the smp_load_acquire() issued by a CPU in29102910- * kick_cpus_irq_workfn() who is waiting for this CPU to perform a29112911- * resched.29122912- */29132913- smp_store_release(&rq->scx.pnt_seq, rq->scx.pnt_seq + 1);29142914-#endif29152915- if (!static_branch_unlikely(&scx_ops_cpu_preempt))29162916- return;29172917-29182918- /*29192919- * The callback is conceptually meant to convey that the CPU is no29202920- * longer under the control of SCX. Therefore, don't invoke the callback29212921- * if the next class is below SCX (in which case the BPF scheduler has29222922- * actively decided not to schedule any tasks on the CPU).29232923- */29242924- if (sched_class_above(&ext_sched_class, next_class))29252925- return;29262926-29272927- /*29282928- * At this point we know that SCX was preempted by a higher priority29292929- * sched_class, so invoke the ->cpu_release() callback if we have not29302930- * done so already. We only send the callback once between SCX being29312931- * preempted, and it regaining control of the CPU.29322932- *29332933- * ->cpu_release() complements ->cpu_acquire(), which is emitted the29342934- * next time that balance_scx() is invoked.29352935- */29362936- if (!rq->scx.cpu_released) {29372937- if (SCX_HAS_OP(cpu_release)) {29382938- struct scx_cpu_release_args args = {29392939- .reason = preempt_reason_from_class(next_class),29402940- .task = next,29412941- };29422942-29432943- SCX_CALL_OP(SCX_KF_CPU_RELEASE,29442944- cpu_release, cpu_of(rq), &args);29452945- }29462946- rq->scx.cpu_released = true;29472947- }29482948-}2949282329502824#ifdef CONFIG_SMP29512825