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 <quic_shalagra@quicinc.com>
This commit is contained in:
Shaleen Agrawal 2022-05-27 18:51:52 -07:00 committed by Rishabh Bhatnagar
parent 99a0b1fcbc
commit 4014533422
5 changed files with 38 additions and 33 deletions

View File

@ -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;
}

View File

@ -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) {

View File

@ -11,6 +11,12 @@
#include <linux/spinlock_types.h>
#include <linux/cpumask.h>
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;
}

View File

@ -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));

View File

@ -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);