pause: port the users of pause

Port the users of pause from the 5.10 kernel to ensure code is up to date.

Change-Id: Ibe52cc37e0dca425f2f472b9cf254a2453bd9c47
Signed-off-by: Stephen Dickey <dickey@codeaurora.org>
This commit is contained in:
Stephen Dickey 2021-11-01 17:22:09 -07:00 committed by Rishabh Bhatnagar
parent beb88676bf
commit 9c062eae64
7 changed files with 162 additions and 61 deletions

View File

@ -29,6 +29,8 @@
#include <linux/sched/walt.h>
#include <linux/sched/walt.h>
#define MAX_RESERVE_CPUS (num_possible_cpus()/2)
static DEFINE_PER_CPU(struct freq_qos_request, qos_min_req);

View File

@ -41,3 +41,14 @@ config QCOM_LMH
input from temperature and current sensors. On many newer Qualcomm SoCs
LMh is configured in the firmware and this feature need not be enabled.
However, on certain SoCs like sdm845 LMh has to be configured from kernel.
config QTI_CPU_PAUSE_COOLING_DEVICE
tristate "QTI CPU Pause cooling devices"
depends on THERMAL_OF && HOTPLUG_CPU
depends on ARCH_QCOM || COMPILE_TEST
help
This enables the QTI CPU Pause cooling device. These cooling
devices will be used by QTI chipset to pause a CPU from being
scheduled and hence will let the CPU to power collapse. Pausing
a CPU will be used when the CPU frequency mitigation
is not good enough to achieve the necessary cooling.

View File

@ -6,3 +6,4 @@ qcom_tsens-y += tsens.o tsens-v2.o tsens-v1.o tsens-v0_1.o \
obj-$(CONFIG_QCOM_SPMI_ADC_TM5) += qcom-spmi-adc-tm5.o
obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o
obj-$(CONFIG_QCOM_LMH) += lmh.o
obj-$(CONFIG_QTI_CPU_PAUSE_COOLING_DEVICE) += thermal_pause.o

View File

@ -23,14 +23,18 @@ enum thermal_pause_levels {
MAX_THERMAL_PAUSE_LEVEL
};
#define THERMAL_PAUSE_RETRY_COUNT 5
struct thermal_pause_cdev {
struct list_head node;
cpumask_t cpu_mask;
bool thermal_pause_level;
enum thermal_pause_levels thermal_pause_level;
enum thermal_pause_levels thermal_pause_req;
struct thermal_cooling_device *cdev;
struct device_node *np;
char cdev_name[THERMAL_NAME_LENGTH];
struct work_struct reg_work;
struct work_struct pause_update_work;
};
static DEFINE_MUTEX(cpus_pause_lock);
@ -39,22 +43,25 @@ static LIST_HEAD(thermal_pause_cdev_list);
static struct cpumask cpus_in_max_cooling_level;
static enum cpuhp_state cpu_hp_online;
static BLOCKING_NOTIFIER_HEAD(multi_max_cooling_level_notifer);
static BLOCKING_NOTIFIER_HEAD(thermal_pause_notifier);
void cpu_cooling_multi_max_level_notifier_register(struct notifier_block *n)
void thermal_pause_notifier_register(struct notifier_block *n)
{
blocking_notifier_chain_register(&multi_max_cooling_level_notifer, n);
blocking_notifier_chain_register(&thermal_pause_notifier, n);
}
EXPORT_SYMBOL(thermal_pause_notifier_register);
void cpu_cooling_multi_max_level_notifier_unregister(struct notifier_block *n)
void thermal_pause_notifier_unregister(struct notifier_block *n)
{
blocking_notifier_chain_unregister(&multi_max_cooling_level_notifer, n);
blocking_notifier_chain_unregister(&thermal_pause_notifier, n);
}
EXPORT_SYMBOL(thermal_pause_notifier_unregister);
const struct cpumask *cpu_cooling_multi_get_max_level_cpumask(void)
const struct cpumask *thermal_paused_cpumask(void)
{
return &cpus_in_max_cooling_level;
}
EXPORT_SYMBOL(thermal_paused_cpumask);
static int thermal_pause_hp_online(unsigned int online_cpu)
{
@ -76,26 +83,21 @@ static int thermal_pause_hp_online(unsigned int online_cpu)
}
/**
* thermal_pause_cpus_pause - function to pause a group of cpus at
* the specified level.
* thermal_pause_work - work function to pause a group of cpus at
* the specified level.
*
* @thermal_pause_cdev: the pause device
* @thermal_pasue_cdev: the cdev currently being processed
*
* function to handle setting the current cpus paused by
* Function to handle setting the current cpus paused by
* this driver for the mask specified in the device.
* it assumes the mutex is locked.
*
* Returns 0 if CPUs were paused, error otherwise
* it assumes the mutex is locked upon entrance.
*/
static int thermal_pause_cpus_pause(struct thermal_pause_cdev *thermal_pause_cdev)
static int thermal_pause_work(struct thermal_pause_cdev *thermal_pause_cdev)
{
int cpu = 0;
int ret = -EBUSY;
cpumask_t cpus_to_pause, cpus_to_notify;
if (thermal_pause_cdev->thermal_pause_level)
return ret;
cpumask_copy(&cpus_to_pause, &thermal_pause_cdev->cpu_mask);
pr_debug("Pause:%*pbl\n", cpumask_pr_args(&thermal_pause_cdev->cpu_mask));
@ -120,33 +122,29 @@ static int thermal_pause_cpus_pause(struct thermal_pause_cdev *thermal_pause_cde
/* Failure. These cpus not paused by thermal */
pr_err("Error pausing CPU:%*pbl. err:%d\n",
cpumask_pr_args(&thermal_pause_cdev->cpu_mask), ret);
return ret;
}
return ret;
}
/**
* thermal_pause_cpus_unpause - function to unpause a
* thermal_resume_work - work function to unpause a
* group of cpus in the mask for this cdev
*
* @thermal_pause_cdev: the pause device
* @thermal_pasue_cdev: the cdev currently being processed
*
* function to handle enabling the group of cpus in the cdev
*
* Returns 0 if CPUs were unpaused,
* Function to handle enabling the group of cpus in the cdev.
* This is performed as a work function to avoid conflicts
* between a hotplug event invoking a pause cooling device,
* and a thermal event invoking a pause cooling device.
*/
static int thermal_pause_cpus_unpause(struct thermal_pause_cdev *thermal_pause_cdev)
static int thermal_resume_work(struct thermal_pause_cdev *thermal_pause_cdev)
{
int cpu = 0;
int ret = -ENODEV;
cpumask_t cpus_to_unpause, new_paused_cpus, cpus_to_notify;
struct thermal_pause_cdev *cdev;
/* do not unpause a cooling device not paused */
if (!thermal_pause_cdev->thermal_pause_level)
return ret;
cpumask_copy(&cpus_to_unpause, &thermal_pause_cdev->cpu_mask);
pr_debug("Unpause:%*pbl\n", cpumask_pr_args(&cpus_to_unpause));
@ -177,12 +175,73 @@ static int thermal_pause_cpus_unpause(struct thermal_pause_cdev *thermal_pause_c
/* Failure. Ref-count for cpus controlled by thermal still set */
pr_err("Error resuming CPU:%*pbl. err:%d\n",
cpumask_pr_args(&thermal_pause_cdev->cpu_mask), ret);
return ret;
}
return ret;
}
/**
* thermal_pause_set_update_work: Enforce Requested State
*
* @work: the work structure for this work
*
* Enforce the most recent requested cooling state, if
* it is a mismatch with the current state. Since the
* request is made in a different context from the
* enforcement, it is possible to have an updated request
* after completing the resume/pause request.
*
* Handle a post-operation mismatch between the cooling state
* and the requested state.
*
* This is performed as a work function to avoid conflicts
* between a hotplug event invoking a pause cooling device,
* and a thermal event invoking a pause cooling device.
*/
static void thermal_pause_update_work(struct work_struct *work)
{
int ret = 0;
int retcnt = THERMAL_PAUSE_RETRY_COUNT;
struct thermal_pause_cdev *thermal_pause_cdev =
container_of(work, struct thermal_pause_cdev, pause_update_work);
mutex_lock(&cpus_pause_lock);
retry:
if (thermal_pause_cdev->thermal_pause_req != thermal_pause_cdev->thermal_pause_level) {
if (thermal_pause_cdev->thermal_pause_req == THERMAL_NO_CPU_PAUSE) {
ret = thermal_resume_work(thermal_pause_cdev);
if (ret >= 0)
thermal_pause_cdev->thermal_pause_level = THERMAL_NO_CPU_PAUSE;
} else {
ret = thermal_pause_work(thermal_pause_cdev);
if (ret >= 0)
thermal_pause_cdev->thermal_pause_level = THERMAL_GROUP_CPU_PAUSE;
}
if (ret < 0 && retcnt > 0) {
retcnt--;
goto retry;
}
}
/*
* if the pause/resume operation itself failed (and failed THERMAL_PAUSE_RETRY_COUNT
* times) then ret will be negative here. Do not repeatedly retry if pause itself
* failed, because this can happen indefinitely.
*
* If instead the pause request has been toggled back and forth many times by
* the thermal framework, this can be handled here.
*/
if (ret >= 0 &&
thermal_pause_cdev->thermal_pause_req != thermal_pause_cdev->thermal_pause_level) {
pr_debug("Pause: requested state changed while workfn running\n");
retcnt = THERMAL_PAUSE_RETRY_COUNT;
goto retry;
}
mutex_unlock(&cpus_pause_lock);
}
/**
* thermal_pause_set_cur_state - callback function to set the current cooling
* level.
@ -190,7 +249,8 @@ static int thermal_pause_cpus_unpause(struct thermal_pause_cdev *thermal_pause_c
* @level: set this variable to the current cooling level.
*
* Callback for the thermal cooling device to change the cpu pause
* current cooling level.
* current cooling level, by making a requested and queueing the
* work to be done.
*
* Return: 0 on success, an error code otherwise.
*/
@ -198,29 +258,22 @@ static int thermal_pause_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long level)
{
struct thermal_pause_cdev *thermal_pause_cdev = cdev->devdata;
int ret = 0;
if (level >= MAX_THERMAL_PAUSE_LEVEL)
return -EINVAL;
if (thermal_pause_cdev->thermal_pause_level == level)
return 0;
mutex_lock(&cpus_pause_lock);
if (level == THERMAL_GROUP_CPU_PAUSE)
ret = thermal_pause_cpus_pause(thermal_pause_cdev);
if (level)
thermal_pause_cdev->thermal_pause_req = THERMAL_GROUP_CPU_PAUSE;
else
ret = thermal_pause_cpus_unpause(thermal_pause_cdev);
/*
* only change the pause level if things were successful. Otherwise
* an unsuccessful pause operation can be followed by a resume
* operation, resuming cpus not paused by this cooling device.
*/
if (ret == 0)
thermal_pause_cdev->thermal_pause_level = level;
thermal_pause_cdev->thermal_pause_req = THERMAL_NO_CPU_PAUSE;
queue_work(system_highpri_wq, &thermal_pause_cdev->pause_update_work);
mutex_unlock(&cpus_pause_lock);
return ret;
return 0;
}
/**
@ -307,6 +360,7 @@ static int thermal_pause_probe(struct platform_device *pdev)
struct of_phandle_iterator it;
cpumask_t cpu_mask;
unsigned long mask = 0;
const char *alias;
INIT_LIST_HEAD(&thermal_pause_cdev_list);
cpumask_clear(&cpus_in_max_cooling_level);
@ -339,17 +393,22 @@ static int thermal_pause_probe(struct platform_device *pdev)
of_node_put(subsys_np);
return -ENOMEM;
}
snprintf(thermal_pause_cdev->cdev_name, THERMAL_NAME_LENGTH,
ret = of_property_read_string(subsys_np,
"qcom,cdev-alias", &alias);
if (ret)
snprintf(thermal_pause_cdev->cdev_name, THERMAL_NAME_LENGTH,
"thermal-pause-%X", mask);
else
strscpy(thermal_pause_cdev->cdev_name, alias,
THERMAL_NAME_LENGTH);
thermal_pause_cdev->thermal_pause_level = false;
thermal_pause_cdev->cdev = NULL;
thermal_pause_cdev->np = subsys_np;
cpumask_copy(&thermal_pause_cdev->cpu_mask, &cpu_mask);
INIT_WORK(&thermal_pause_cdev->reg_work,
thermal_pause_register_cdev);
INIT_WORK(&thermal_pause_cdev->reg_work, thermal_pause_register_cdev);
INIT_WORK(&thermal_pause_cdev->pause_update_work, thermal_pause_update_work);
list_add(&thermal_pause_cdev->node, &thermal_pause_cdev_list);
}
@ -378,13 +437,8 @@ static int thermal_pause_remove(struct platform_device *pdev)
/* for each asserted cooling device, resume the CPUs */
if (thermal_pause_cdev->thermal_pause_level) {
mutex_unlock(&cpus_pause_lock);
ret = walt_resume_cpus(&thermal_pause_cdev->cpu_mask);
if (ret < 0)
pr_err("Error resuming CPU:%*pbl. err:%d\n",
cpumask_pr_args(&thermal_pause_cdev->cpu_mask), ret);
mutex_lock(&cpus_pause_lock);
thermal_pause_cdev->thermal_pause_req = THERMAL_NO_CPU_PAUSE;
queue_work(system_highpri_wq, &thermal_pause_cdev->pause_update_work);
}
if (thermal_pause_cdev->cdev)

View File

@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*/
#ifndef _LINUX_THERMAL_PAUSE_H
#define _LINUX_THERMAL_PAUSE_H
#include <linux/notifier.h>
#include <linux/cpumask.h>
#if IS_ENABLED(CONFIG_QTI_CPU_PAUSE_COOLING_DEVICE)
extern void thermal_pause_notifier_register(struct notifier_block *n);
extern void thermal_pause_notifier_unregister(struct notifier_block *n);
extern const struct cpumask *thermal_paused_cpumask(void);
#else
static inline
void thermal_pause_notifier_register(struct notifier_block *n)
{
}
static inline
void thermal_pause_notifier_unregister(struct notifier_block *n)
{
}
static inline const struct cpumask *thermal_paused_cpumask(void)
{
return cpu_none_mask;
}
#endif /* CONFIG_QTI_CPU_PAUSE_COOLING_DEVICE */
#endif /* _LINUX_THERMAL_PAUSE_H */

View File

@ -4,7 +4,7 @@ KCOV_INSTRUMENT := n
KCSAN_SANITIZE := n
obj-$(CONFIG_SCHED_WALT) += sched-walt.o
sched-walt-$(CONFIG_SCHED_WALT) := walt.o boost.o sched_avg.o walt_pause.o core_ctl.o trace.o input-boost.o sysctl.o cpufreq_walt.o fixup.o walt_lb.o walt_rt.o walt_cfs.o walt_tp.o
sched-walt-$(CONFIG_SCHED_WALT) := walt.o boost.o sched_avg.o walt_pause.o core_ctl.o trace.o input-boost.o sysctl.o cpufreq_walt.o fixup.o walt_lb.o walt_rt.o walt_cfs.o
obj-$(CONFIG_SCHED_WALT_DEBUG) += sched-walt-debug.o
sched-walt-debug-$(CONFIG_SCHED_WALT_DEBUG) := walt_debug.o preemptirq_long.o

View File

@ -66,7 +66,7 @@ int walt_pause_cpus(struct cpumask *cpus)
goto unlock;
}
ret = pause_cpus(cpus);
// ret = pause_cpus(cpus);
if (ret < 0)
pr_debug("pause_cpus failure ret=%d cpus=%*pbl\n", ret,
cpumask_pr_args(&requested_cpus));
@ -95,7 +95,7 @@ int walt_resume_cpus(struct cpumask *cpus)
if (cpumask_empty(cpus))
goto unlock;
ret = resume_cpus(cpus);
// ret = resume_cpus(cpus);
if (ret < 0) {
pr_debug("resume_cpus failure ret=%d cpus=%*pbl\n", ret,
cpumask_pr_args(&requested_cpus));
@ -156,7 +156,7 @@ static void walt_pause_online_workfn(struct work_struct *work)
if (cpumask_empty(&re_pause_cpus))
goto unlock;
ret = pause_cpus(&re_pause_cpus);
//ret = pause_cpus(&re_pause_cpus);
unlock:
mutex_unlock(&pause_lock);