mirror of
https://github.com/torvalds/linux.git
synced 2026-07-30 19:21:28 +02:00
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:
parent
beb88676bf
commit
9c062eae64
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
33
include/linux/thermal_pause.h
Normal file
33
include/linux/thermal_pause.h
Normal 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 */
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user