sched/pause: handle cpu online processing for pause

With refcounting, the walt wrapper for pause/resume can keep
track of whether a CPU should be paused or not, where this
information used to be distributed to the clients using the api.

Simplify the design, such that a CPU is automatically paused
as it is coming online, affecting the active/inactive state of
the CPU, but not adjusting the ref-counts.

Going forward, client software using walt_pause/walt_resume
will not be required to keep track of the online state of a
cpu.

Change-Id: I83e3cc8743942c3a482eb588546b6ea9bb7bf2e3
Signed-off-by: Stephen Dickey <dickey@codeaurora.org>
This commit is contained in:
Stephen Dickey 2021-02-12 10:01:33 -08:00 committed by Rishabh Bhatnagar
parent e483442bb7
commit 17444a20e3
4 changed files with 85 additions and 43 deletions

View File

@ -35,9 +35,12 @@ struct thermal_pause_cdev {
static DEFINE_MUTEX(cpus_pause_lock);
static LIST_HEAD(thermal_pause_cdev_list);
/* track cpus that thermal intends to pause, regardless of
* whether thermal was requesting an already paused cpu
*/
static struct cpumask cpus_paused_by_thermal;
static struct cpumask cpus_in_max_cooling_level;
static struct cpumask cpus_pending_online;
static enum cpuhp_state cpu_hp_online;
static BLOCKING_NOTIFIER_HEAD(multi_max_cooling_level_notifer);
@ -62,17 +65,11 @@ static int thermal_pause_hp_online(unsigned int online_cpu)
struct thermal_pause_cdev *thermal_pause_cdev;
int ret = 0;
pr_debug("online entry CPU:%d. mask:%*pbl pend:%*pbl\n", online_cpu,
cpumask_pr_args(&cpus_paused_by_thermal),
cpumask_pr_args(&cpus_pending_online));
pr_debug("online entry CPU:%d. mask:%*pbl\n", online_cpu,
cpumask_pr_args(&cpus_paused_by_thermal));
mutex_lock(&cpus_pause_lock);
if (cpumask_test_cpu(online_cpu, &cpus_paused_by_thermal)) {
ret = NOTIFY_BAD;
cpumask_set_cpu(online_cpu, &cpus_pending_online);
}
list_for_each_entry(thermal_pause_cdev, &thermal_pause_cdev_list, node) {
if (cpumask_test_cpu(online_cpu, &thermal_pause_cdev->cpu_mask)
&& !thermal_pause_cdev->cdev)
@ -81,9 +78,8 @@ static int thermal_pause_hp_online(unsigned int online_cpu)
}
mutex_unlock(&cpus_pause_lock);
pr_debug("online exit CPU:%d. mask:%*pbl pend:%*pbl\n", online_cpu,
cpumask_pr_args(&cpus_paused_by_thermal),
cpumask_pr_args(&cpus_pending_online));
pr_debug("online exit CPU:%d. mask:%*pbl\n", online_cpu,
cpumask_pr_args(&cpus_paused_by_thermal));
return ret;
}
@ -150,7 +146,7 @@ static int thermal_pause_cpus_unpause(struct thermal_pause_cdev *thermal_pause_c
int cpu = 0;
int ret = -ENODEV;
struct thermal_pause_cdev *cdev;
cpumask_t cpus_offlined, new_cpu_pause, cpus_to_unpause;
cpumask_t new_cpu_pause, cpus_to_unpause;
cpumask_clear(&new_cpu_pause);
list_for_each_entry(cdev, &thermal_pause_cdev_list, node) {
@ -162,14 +158,10 @@ static int thermal_pause_cpus_unpause(struct thermal_pause_cdev *thermal_pause_c
cpumask_andnot(&cpus_to_unpause, &cpus_paused_by_thermal,
&new_cpu_pause);
cpumask_and(&cpus_offlined, &cpus_pending_online,
&cpus_to_unpause);
pr_debug("Old req:%*pbl New req:%*pbl Unpause:%*pbl Online:%*pbl\n",
pr_debug("Old req:%*pbl New req:%*pbl Unpause:%*pbl\n",
cpumask_pr_args(&cpus_paused_by_thermal),
cpumask_pr_args(&new_cpu_pause),
cpumask_pr_args(&cpus_to_unpause),
cpumask_pr_args(&cpus_offlined));
cpumask_pr_args(&cpus_to_unpause));
cpumask_copy(&cpus_in_max_cooling_level, &new_cpu_pause);
cpumask_copy(&cpus_paused_by_thermal, &new_cpu_pause);
@ -183,15 +175,6 @@ static int thermal_pause_cpus_unpause(struct thermal_pause_cdev *thermal_pause_c
mutex_lock(&cpus_pause_lock);
}
for_each_cpu(cpu, &cpus_offlined) {
cpumask_clear_cpu(cpu, &cpus_pending_online);
mutex_unlock(&cpus_pause_lock);
ret = add_cpu(cpu);
if (ret)
pr_err("Error Adding CPU:%d. err:%d\n", cpu, ret);
mutex_lock(&cpus_pause_lock);
}
for_each_cpu(cpu, &cpus_to_unpause)
blocking_notifier_call_chain(
&multi_max_cooling_level_notifer,
@ -326,7 +309,6 @@ static int thermal_pause_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&thermal_pause_cdev_list);
cpumask_clear(&cpus_in_max_cooling_level);
cpumask_clear(&cpus_paused_by_thermal);
cpumask_clear(&cpus_pending_online);
for_each_available_child_of_node(np, subsys_np) {
@ -382,7 +364,7 @@ static int thermal_pause_probe(struct platform_device *pdev)
static int thermal_pause_remove(struct platform_device *pdev)
{
struct thermal_pause_cdev *thermal_pause_cdev = NULL, *next = NULL;
int ret = 0, cpu = 0;
int ret = 0;
if (cpu_hp_online) {
cpuhp_remove_state_nocalls(cpu_hp_online);
@ -398,26 +380,15 @@ static int thermal_pause_remove(struct platform_device *pdev)
list_del(&thermal_pause_cdev->node);
}
cpumask_andnot(&cpus_paused_by_thermal, &cpus_paused_by_thermal,
&cpus_pending_online);
if (!cpumask_empty(&cpus_paused_by_thermal)) {
mutex_unlock(&cpus_pause_lock);
ret = walt_resume_cpus(&cpus_paused_by_thermal);
if (ret)
if (ret < 0)
pr_err("Error resuming CPU:%*pbl. err:%d\n",
cpumask_pr_args(&cpus_paused_by_thermal), ret);
mutex_lock(&cpus_pause_lock);
}
for_each_cpu(cpu, &cpus_pending_online) {
mutex_unlock(&cpus_pause_lock);
ret = add_cpu(cpu);
if (ret)
pr_err("Error Adding CPU:%d. err:%d\n", cpu, ret);
mutex_lock(&cpus_pause_lock);
}
mutex_unlock(&cpus_pause_lock);
return 0;

View File

@ -4056,6 +4056,7 @@ static void walt_init(void)
walt_lb_init();
walt_rt_init();
walt_cfs_init();
walt_pause_init();
stop_machine(walt_init_stop_handler, NULL, NULL);

View File

@ -732,6 +732,7 @@ extern void sched_update_hyst_times(void);
extern enum sched_boost_policy sched_boost_policy(void);
extern void walt_rt_init(void);
extern void walt_cfs_init(void);
extern void walt_pause_init(void);
extern void walt_fixup_init(void);
extern int walt_find_energy_efficient_cpu(struct task_struct *p, int prev_cpu,
int sync, int sibling_count_hint);

View File

@ -60,8 +60,12 @@ int walt_pause_cpus(struct cpumask *cpus)
cpumask_copy(&saved_cpus, cpus);
/* prior to operation, track cpus requested to be paused */
/* add ref counts for all cpus in mask */
inc_ref_counts(cpus);
/* only actually pause online CPUs */
cpumask_and(cpus, cpus, cpu_online_mask);
ret = pause_cpus(cpus);
if (ret < 0) {
dec_test_ref_counts(&saved_cpus);
@ -81,7 +85,12 @@ int walt_resume_cpus(struct cpumask *cpus)
cpumask_copy(&saved_cpus, cpus);
/* remove ref counts for all cpus in mask */
dec_test_ref_counts(cpus);
/* only actually resume online CPUs */
cpumask_and(cpus, cpus, cpu_online_mask);
ret = resume_cpus(cpus);
if (ret < 0) {
inc_ref_counts(&saved_cpus);
@ -93,4 +102,64 @@ int walt_resume_cpus(struct cpumask *cpus)
}
EXPORT_SYMBOL(walt_resume_cpus);
struct work_struct walt_pause_online_work;
/* workfn to perform re-pause operation by detecting
* ref-counts and attempting to restore the state.
* It must not adjust the ref-counts for each cpu, or
* the actual paused state will no longer reflect client's
* expectations.
*/
static void walt_pause_online_workfn(struct work_struct *work)
{
struct pause_cpu_state *pause_cpu_state;
cpumask_t re_pause_cpus;
int cpu, ret = 0;
cpumask_clear(&re_pause_cpus);
/* search and test all online cpus */
spin_lock(&pause_lock);
for_each_online_cpu(cpu) {
pause_cpu_state = per_cpu_ptr(&pause_state, cpu);
if (pause_cpu_state->ref_count)
cpumask_set_cpu(cpu, &re_pause_cpus);
}
spin_unlock(&pause_lock);
if (cpumask_empty(&re_pause_cpus))
return;
/* will wait for existing hp operations to complete */
ret = pause_cpus(&re_pause_cpus);
if (ret < 0) {
pr_err("pause_cpus during online failure ret=%d cpus=%*pb1\n", ret,
cpumask_pr_args(&re_pause_cpus));
}
}
/* do not perform online work in hotplug context */
static int walt_pause_hp_online(unsigned int online_cpu)
{
struct pause_cpu_state *pause_cpu_state;
pause_cpu_state = per_cpu_ptr(&pause_state, online_cpu);
if (pause_cpu_state->ref_count)
schedule_work(&walt_pause_online_work);
return 0;
}
void walt_pause_init(void)
{
int ret;
INIT_WORK(&walt_pause_online_work, walt_pause_online_workfn);
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "walt-pause/online",
walt_pause_hp_online, NULL);
if (ret < 0)
pr_err("failure to register cpuhp online state ret=%d\n", ret);
}
#endif /* CONFIG_HOTPLUG_CPU */