From 401453342220f3f47414709cbcbbf87b269b68c6 Mon Sep 17 00:00:00 2001 From: Shaleen Agrawal Date: Fri, 27 May 2022 18:51:52 -0700 Subject: [PATCH] sched/walt/halt: track halt reasons Currently, there are no protections under conditions where CPUs may be halted or unhalted twice, which could lead to undesired behavior. Track reasons for refcounts per CPU to ensure proper accounting. Change-Id: Ic85a13f3536e3287fc76a02004d2b4601ada7a1a Signed-off-by: Shaleen Agrawal --- drivers/soc/qcom/hyp_core_ctl.c | 4 +-- drivers/thermal/qcom/thermal_pause.c | 4 +-- include/linux/sched/walt.h | 19 ++++++++----- kernel/sched/walt/core_ctl.c | 4 +-- kernel/sched/walt/walt_halt.c | 40 +++++++++++++--------------- 5 files changed, 38 insertions(+), 33 deletions(-) diff --git a/drivers/soc/qcom/hyp_core_ctl.c b/drivers/soc/qcom/hyp_core_ctl.c index c5a00da88e9a..2e490c09b561 100644 --- a/drivers/soc/qcom/hyp_core_ctl.c +++ b/drivers/soc/qcom/hyp_core_ctl.c @@ -109,7 +109,7 @@ static inline int pause_cpu(int cpu) cpumask_clear(&cpus_to_pause); cpumask_set_cpu(cpu, &cpus_to_pause); - ret = walt_pause_cpus(&cpus_to_pause); + ret = walt_pause_cpus(&cpus_to_pause, PAUSE_HYP); return ret; } @@ -122,7 +122,7 @@ static inline int resume_cpu(int cpu) cpumask_clear(&cpus_to_resume); cpumask_set_cpu(cpu, &cpus_to_resume); - ret = walt_resume_cpus(&cpus_to_resume); + ret = walt_resume_cpus(&cpus_to_resume, PAUSE_HYP); return ret; } diff --git a/drivers/thermal/qcom/thermal_pause.c b/drivers/thermal/qcom/thermal_pause.c index 0c926c220c94..5e367cb59cd4 100644 --- a/drivers/thermal/qcom/thermal_pause.c +++ b/drivers/thermal/qcom/thermal_pause.c @@ -102,7 +102,7 @@ static int thermal_pause_work(struct thermal_pause_cdev *thermal_pause_cdev) pr_debug("Pause:%*pbl\n", cpumask_pr_args(&thermal_pause_cdev->cpu_mask)); mutex_unlock(&cpus_pause_lock); - ret = walt_pause_cpus(&cpus_to_pause); + ret = walt_pause_cpus(&cpus_to_pause, PAUSE_THERMAL); mutex_lock(&cpus_pause_lock); if (ret == 0) { @@ -149,7 +149,7 @@ static int thermal_resume_work(struct thermal_pause_cdev *thermal_pause_cdev) pr_debug("Unpause:%*pbl\n", cpumask_pr_args(&cpus_to_unpause)); mutex_unlock(&cpus_pause_lock); - ret = walt_resume_cpus(&cpus_to_unpause); + ret = walt_resume_cpus(&cpus_to_unpause, PAUSE_THERMAL); mutex_lock(&cpus_pause_lock); if (ret == 0) { diff --git a/include/linux/sched/walt.h b/include/linux/sched/walt.h index 9bb6ceada1a7..34f771ace147 100644 --- a/include/linux/sched/walt.h +++ b/include/linux/sched/walt.h @@ -11,6 +11,12 @@ #include #include +enum pause_reason { + PAUSE_CORE_CTL = 0x01, + PAUSE_THERMAL = 0x02, + PAUSE_HYP = 0x04, +}; + #if IS_ENABLED(CONFIG_SCHED_WALT) #define MAX_CPUS_PER_CLUSTER 6 @@ -170,10 +176,11 @@ struct notifier_block; extern void core_ctl_notifier_register(struct notifier_block *n); extern void core_ctl_notifier_unregister(struct notifier_block *n); extern int core_ctl_set_boost(bool boost); -extern int walt_pause_cpus(struct cpumask *cpus); -extern int walt_resume_cpus(struct cpumask *cpus); -extern int walt_halt_cpus(struct cpumask *cpus); -extern int walt_start_cpus(struct cpumask *cpus); + +extern int walt_pause_cpus(struct cpumask *cpus, enum pause_reason reason); +extern int walt_resume_cpus(struct cpumask *cpus, enum pause_reason reason); +extern int walt_halt_cpus(struct cpumask *cpus, enum pause_reason reason); +extern int walt_start_cpus(struct cpumask *cpus, enum pause_reason reason); #else static inline int sched_lpm_disallowed_time(int cpu, u64 *timeout) { @@ -211,11 +218,11 @@ static inline void core_ctl_notifier_unregister(struct notifier_block *n) { } -inline int walt_pause_cpus(struct cpumask *cpus) +inline int walt_pause_cpus(struct cpumask *cpus, enum pause_reason reason) { return 0; } -inline int walt_resume_cpus(struct cpumask *cpus) +inline int walt_resume_cpus(struct cpumask *cpus, enum pause_reason reason) { return 0; } diff --git a/kernel/sched/walt/core_ctl.c b/kernel/sched/walt/core_ctl.c index 3bcb59d8f646..cdb123d90b8f 100644 --- a/kernel/sched/walt/core_ctl.c +++ b/kernel/sched/walt/core_ctl.c @@ -1163,7 +1163,7 @@ static void core_ctl_pause_cpus(struct cpumask *cpus_to_pause) cpumask_copy(&saved_cpus, cpus_to_pause); if (cpumask_any(cpus_to_pause) < nr_cpu_ids) { - if (walt_halt_cpus(cpus_to_pause) < 0) + if (walt_halt_cpus(cpus_to_pause, PAUSE_CORE_CTL) < 0) pr_debug("core_ctl pause operation failed cpus=%*pbl paused_by_us=%*pbl\n", cpumask_pr_args(cpus_to_pause), cpumask_pr_args(&cpus_paused_by_us)); @@ -1192,7 +1192,7 @@ static void core_ctl_resume_cpus(struct cpumask *cpus_to_unpause) cpumask_copy(&saved_cpus, cpus_to_unpause); if (cpumask_any(cpus_to_unpause) < nr_cpu_ids) { - if (walt_start_cpus(cpus_to_unpause) < 0) + if (walt_start_cpus(cpus_to_unpause, PAUSE_CORE_CTL) < 0) pr_debug("core_ctl resume operation failed cpus=%*pbl paused_by_us=%*pbl\n", cpumask_pr_args(cpus_to_unpause), cpumask_pr_args(&cpus_paused_by_us)); diff --git a/kernel/sched/walt/walt_halt.c b/kernel/sched/walt/walt_halt.c index 346180098231..f61528ef7cb2 100644 --- a/kernel/sched/walt/walt_halt.c +++ b/kernel/sched/walt/walt_halt.c @@ -20,7 +20,7 @@ static DEFINE_RAW_SPINLOCK(halt_lock); struct halt_cpu_state { u64 last_halt; - int ref_count; + u8 reason; }; static DEFINE_PER_CPU(struct halt_cpu_state, halt_state); @@ -333,20 +333,18 @@ static int start_cpus(struct cpumask *cpus) return 0; } -/* increment/decrement ref count for cpus in yield/halt mask */ -static void update_ref_counts(struct cpumask *cpus, bool halt) +/* update reason for cpus in yield/halt mask */ +static void update_reasons(struct cpumask *cpus, bool halt, enum pause_reason reason) { int cpu; struct halt_cpu_state *halt_cpu_state; for_each_cpu(cpu, cpus) { halt_cpu_state = per_cpu_ptr(&halt_state, cpu); - if (halt) { - halt_cpu_state->ref_count++; - } else { - WARN_ON_ONCE(halt_cpu_state->ref_count == 0); - halt_cpu_state->ref_count--; - } + if (halt) + halt_cpu_state->reason |= reason; + else + halt_cpu_state->reason &= ~reason; } } @@ -358,13 +356,13 @@ static void update_halt_cpus(struct cpumask *cpus) for_each_cpu(cpu, cpus) { halt_cpu_state = per_cpu_ptr(&halt_state, cpu); - if (halt_cpu_state->ref_count) + if (halt_cpu_state->reason) cpumask_clear_cpu(cpu, cpus); } } /* cpus will be modified */ -int walt_halt_cpus(struct cpumask *cpus) +int walt_halt_cpus(struct cpumask *cpus, enum pause_reason reason) { int ret = 0; cpumask_t requested_cpus; @@ -378,7 +376,7 @@ int walt_halt_cpus(struct cpumask *cpus) update_halt_cpus(cpus); if (cpumask_empty(cpus)) { - update_ref_counts(&requested_cpus, true); + update_reasons(&requested_cpus, true, reason); goto unlock; } @@ -388,21 +386,21 @@ int walt_halt_cpus(struct cpumask *cpus) pr_debug("halt_cpus failure ret=%d cpus=%*pbl\n", ret, cpumask_pr_args(&requested_cpus)); else - update_ref_counts(&requested_cpus, true); + update_reasons(&requested_cpus, true, reason); unlock: raw_spin_unlock_irqrestore(&halt_lock, flags); return ret; } -int walt_pause_cpus(struct cpumask *cpus) +int walt_pause_cpus(struct cpumask *cpus, enum pause_reason reason) { - return walt_halt_cpus(cpus); + return walt_halt_cpus(cpus, reason); } EXPORT_SYMBOL(walt_pause_cpus); /* cpus will be modified */ -int walt_start_cpus(struct cpumask *cpus) +int walt_start_cpus(struct cpumask *cpus, enum pause_reason reason) { int ret = 0; cpumask_t requested_cpus; @@ -410,9 +408,9 @@ int walt_start_cpus(struct cpumask *cpus) raw_spin_lock_irqsave(&halt_lock, flags); cpumask_copy(&requested_cpus, cpus); - update_ref_counts(&requested_cpus, false); + update_reasons(&requested_cpus, false, reason); - /* remove cpus that should still be halted, due to ref-counts */ + /* remove cpus that should still be halted */ update_halt_cpus(cpus); ret = start_cpus(cpus); @@ -421,7 +419,7 @@ int walt_start_cpus(struct cpumask *cpus) pr_debug("halt_cpus failure ret=%d cpus=%*pbl\n", ret, cpumask_pr_args(&requested_cpus)); /* restore/increment ref counts in case of error */ - update_ref_counts(&requested_cpus, true); + update_reasons(&requested_cpus, true, reason); } raw_spin_unlock_irqrestore(&halt_lock, flags); @@ -429,9 +427,9 @@ int walt_start_cpus(struct cpumask *cpus) return ret; } -int walt_resume_cpus(struct cpumask *cpus) +int walt_resume_cpus(struct cpumask *cpus, enum pause_reason reason) { - return walt_start_cpus(cpus); + return walt_start_cpus(cpus, reason); } EXPORT_SYMBOL(walt_resume_cpus);