thermal: cpu_cooling: use cpufreq_policy to register cooling device
The CPU cooling driver uses the cpufreq policy, to get clip_cpus, the frequency table, etc. Most of the callers of CPU cooling driver's registration routines have the cpufreq policy with them, but they only pass the policy->related_cpus cpumask. The __cpufreq_cooling_register() routine then gets the policy by itself and uses it. It would be much better if the callers can pass the policy instead directly. This also fixes a basic design flaw, where the policy can be freed while the CPU cooling driver is still active. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Reviewed-by: Lukasz Luba <lukasz.luba@arm.com> Tested-by: Lukasz Luba <lukasz.luba@arm.com> Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
This commit is contained in:
parent
18f301c934
commit
4d753aa7b6
9 changed files with 74 additions and 70 deletions
|
@ -540,7 +540,7 @@ static void bL_cpufreq_ready(struct cpufreq_policy *policy)
|
|||
&power_coefficient);
|
||||
|
||||
cdev[cur_cluster] = of_cpufreq_power_cooling_register(np,
|
||||
policy->related_cpus, power_coefficient, NULL);
|
||||
policy, power_coefficient, NULL);
|
||||
if (IS_ERR(cdev[cur_cluster])) {
|
||||
dev_err(cpu_dev,
|
||||
"running cpufreq without cooling device: %ld\n",
|
||||
|
|
|
@ -326,7 +326,7 @@ static void cpufreq_ready(struct cpufreq_policy *policy)
|
|||
&power_coefficient);
|
||||
|
||||
priv->cdev = of_cpufreq_power_cooling_register(np,
|
||||
policy->related_cpus, power_coefficient, NULL);
|
||||
policy, power_coefficient, NULL);
|
||||
if (IS_ERR(priv->cdev)) {
|
||||
dev_err(priv->cpu_dev,
|
||||
"running cpufreq without cooling device: %ld\n",
|
||||
|
|
|
@ -43,7 +43,7 @@ static int dbx500_cpufreq_exit(struct cpufreq_policy *policy)
|
|||
|
||||
static void dbx500_cpufreq_ready(struct cpufreq_policy *policy)
|
||||
{
|
||||
cdev = cpufreq_cooling_register(policy->cpus);
|
||||
cdev = cpufreq_cooling_register(policy);
|
||||
if (IS_ERR(cdev))
|
||||
pr_err("Failed to register cooling device %ld\n", PTR_ERR(cdev));
|
||||
else
|
||||
|
|
|
@ -320,9 +320,7 @@ static void mtk_cpufreq_ready(struct cpufreq_policy *policy)
|
|||
of_property_read_u32(np, DYNAMIC_POWER, &capacitance);
|
||||
|
||||
info->cdev = of_cpufreq_power_cooling_register(np,
|
||||
policy->related_cpus,
|
||||
capacitance,
|
||||
NULL);
|
||||
policy, capacitance, NULL);
|
||||
|
||||
if (IS_ERR(info->cdev)) {
|
||||
dev_err(info->cpu_dev,
|
||||
|
|
|
@ -278,8 +278,7 @@ static void qoriq_cpufreq_ready(struct cpufreq_policy *policy)
|
|||
struct device_node *np = of_get_cpu_node(policy->cpu, NULL);
|
||||
|
||||
if (of_find_property(np, "#cooling-cells", NULL)) {
|
||||
cpud->cdev = of_cpufreq_cooling_register(np,
|
||||
policy->related_cpus);
|
||||
cpud->cdev = of_cpufreq_cooling_register(np, policy);
|
||||
|
||||
if (IS_ERR(cpud->cdev) && PTR_ERR(cpud->cdev) != -ENOSYS) {
|
||||
pr_err("cpu%d is not running as cooling device: %ld\n",
|
||||
|
|
|
@ -717,7 +717,7 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table,
|
|||
/**
|
||||
* __cpufreq_cooling_register - helper function to create cpufreq cooling device
|
||||
* @np: a valid struct device_node to the cooling device device tree node
|
||||
* @clip_cpus: cpumask of cpus where the frequency constraints will happen.
|
||||
* @policy: cpufreq policy
|
||||
* Normally this should be same as cpufreq policy->related_cpus.
|
||||
* @capacitance: dynamic power coefficient for these cpus
|
||||
* @plat_static_func: function to calculate the static power consumed by these
|
||||
|
@ -733,45 +733,34 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table,
|
|||
*/
|
||||
static struct thermal_cooling_device *
|
||||
__cpufreq_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus, u32 capacitance,
|
||||
struct cpufreq_policy *policy, u32 capacitance,
|
||||
get_static_t plat_static_func)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct cpufreq_cooling_device *cpufreq_cdev;
|
||||
char dev_name[THERMAL_NAME_LENGTH];
|
||||
struct cpufreq_frequency_table *pos, *table;
|
||||
cpumask_var_t temp_mask;
|
||||
unsigned int freq, i, num_cpus;
|
||||
int ret;
|
||||
struct thermal_cooling_device_ops *cooling_ops;
|
||||
bool first;
|
||||
|
||||
if (!alloc_cpumask_var(&temp_mask, GFP_KERNEL))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
cpumask_and(temp_mask, clip_cpus, cpu_online_mask);
|
||||
policy = cpufreq_cpu_get(cpumask_first(temp_mask));
|
||||
if (!policy) {
|
||||
pr_debug("%s: CPUFreq policy not found\n", __func__);
|
||||
cdev = ERR_PTR(-EPROBE_DEFER);
|
||||
goto free_cpumask;
|
||||
if (IS_ERR_OR_NULL(policy)) {
|
||||
pr_err("%s: cpufreq policy isn't valid: %p", __func__, policy);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
table = policy->freq_table;
|
||||
if (!table) {
|
||||
pr_debug("%s: CPUFreq table not found\n", __func__);
|
||||
cdev = ERR_PTR(-ENODEV);
|
||||
goto put_policy;
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
cpufreq_cdev = kzalloc(sizeof(*cpufreq_cdev), GFP_KERNEL);
|
||||
if (!cpufreq_cdev) {
|
||||
cdev = ERR_PTR(-ENOMEM);
|
||||
goto put_policy;
|
||||
}
|
||||
if (!cpufreq_cdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
num_cpus = cpumask_weight(clip_cpus);
|
||||
num_cpus = cpumask_weight(policy->related_cpus);
|
||||
cpufreq_cdev->time_in_idle = kcalloc(num_cpus,
|
||||
sizeof(*cpufreq_cdev->time_in_idle),
|
||||
GFP_KERNEL);
|
||||
|
@ -802,7 +791,7 @@ __cpufreq_cooling_register(struct device_node *np,
|
|||
/* max_level is an index, not a counter */
|
||||
cpufreq_cdev->max_level--;
|
||||
|
||||
cpumask_copy(&cpufreq_cdev->allowed_cpus, clip_cpus);
|
||||
cpumask_copy(&cpufreq_cdev->allowed_cpus, policy->related_cpus);
|
||||
|
||||
if (capacitance) {
|
||||
cpufreq_cdev->plat_get_static_power = plat_static_func;
|
||||
|
@ -858,7 +847,7 @@ __cpufreq_cooling_register(struct device_node *np,
|
|||
cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
|
||||
goto put_policy;
|
||||
return cdev;
|
||||
|
||||
remove_ida:
|
||||
ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
|
||||
|
@ -872,16 +861,12 @@ free_time_in_idle:
|
|||
kfree(cpufreq_cdev->time_in_idle);
|
||||
free_cdev:
|
||||
kfree(cpufreq_cdev);
|
||||
put_policy:
|
||||
cpufreq_cpu_put(policy);
|
||||
free_cpumask:
|
||||
free_cpumask_var(temp_mask);
|
||||
return cdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* cpufreq_cooling_register - function to create cpufreq cooling device.
|
||||
* @clip_cpus: cpumask of cpus where the frequency constraints will happen.
|
||||
* @policy: cpufreq policy
|
||||
*
|
||||
* This interface function registers the cpufreq cooling device with the name
|
||||
* "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
|
||||
|
@ -891,16 +876,16 @@ free_cpumask:
|
|||
* on failure, it returns a corresponding ERR_PTR().
|
||||
*/
|
||||
struct thermal_cooling_device *
|
||||
cpufreq_cooling_register(const struct cpumask *clip_cpus)
|
||||
cpufreq_cooling_register(struct cpufreq_policy *policy)
|
||||
{
|
||||
return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL);
|
||||
return __cpufreq_cooling_register(NULL, policy, 0, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
|
||||
|
||||
/**
|
||||
* of_cpufreq_cooling_register - function to create cpufreq cooling device.
|
||||
* @np: a valid struct device_node to the cooling device device tree node
|
||||
* @clip_cpus: cpumask of cpus where the frequency constraints will happen.
|
||||
* @policy: cpufreq policy
|
||||
*
|
||||
* This interface function registers the cpufreq cooling device with the name
|
||||
* "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
|
||||
|
@ -912,18 +897,18 @@ EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
|
|||
*/
|
||||
struct thermal_cooling_device *
|
||||
of_cpufreq_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus)
|
||||
struct cpufreq_policy *policy)
|
||||
{
|
||||
if (!np)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return __cpufreq_cooling_register(np, clip_cpus, 0, NULL);
|
||||
return __cpufreq_cooling_register(np, policy, 0, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
|
||||
|
||||
/**
|
||||
* cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions
|
||||
* @clip_cpus: cpumask of cpus where the frequency constraints will happen
|
||||
* @policy: cpufreq policy
|
||||
* @capacitance: dynamic power coefficient for these cpus
|
||||
* @plat_static_func: function to calculate the static power consumed by these
|
||||
* cpus (optional)
|
||||
|
@ -943,10 +928,10 @@ EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
|
|||
* on failure, it returns a corresponding ERR_PTR().
|
||||
*/
|
||||
struct thermal_cooling_device *
|
||||
cpufreq_power_cooling_register(const struct cpumask *clip_cpus, u32 capacitance,
|
||||
cpufreq_power_cooling_register(struct cpufreq_policy *policy, u32 capacitance,
|
||||
get_static_t plat_static_func)
|
||||
{
|
||||
return __cpufreq_cooling_register(NULL, clip_cpus, capacitance,
|
||||
return __cpufreq_cooling_register(NULL, policy, capacitance,
|
||||
plat_static_func);
|
||||
}
|
||||
EXPORT_SYMBOL(cpufreq_power_cooling_register);
|
||||
|
@ -954,7 +939,7 @@ EXPORT_SYMBOL(cpufreq_power_cooling_register);
|
|||
/**
|
||||
* of_cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions
|
||||
* @np: a valid struct device_node to the cooling device device tree node
|
||||
* @clip_cpus: cpumask of cpus where the frequency constraints will happen
|
||||
* @policy: cpufreq policy
|
||||
* @capacitance: dynamic power coefficient for these cpus
|
||||
* @plat_static_func: function to calculate the static power consumed by these
|
||||
* cpus (optional)
|
||||
|
@ -976,14 +961,14 @@ EXPORT_SYMBOL(cpufreq_power_cooling_register);
|
|||
*/
|
||||
struct thermal_cooling_device *
|
||||
of_cpufreq_power_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus,
|
||||
struct cpufreq_policy *policy,
|
||||
u32 capacitance,
|
||||
get_static_t plat_static_func)
|
||||
{
|
||||
if (!np)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return __cpufreq_cooling_register(np, clip_cpus, capacitance,
|
||||
return __cpufreq_cooling_register(np, policy, capacitance,
|
||||
plat_static_func);
|
||||
}
|
||||
EXPORT_SYMBOL(of_cpufreq_power_cooling_register);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpu_cooling.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
|
@ -88,6 +89,7 @@ static struct thermal_soc_data thermal_imx6sx_data = {
|
|||
};
|
||||
|
||||
struct imx_thermal_data {
|
||||
struct cpufreq_policy *policy;
|
||||
struct thermal_zone_device *tz;
|
||||
struct thermal_cooling_device *cdev;
|
||||
enum thermal_device_mode mode;
|
||||
|
@ -525,13 +527,18 @@ static int imx_thermal_probe(struct platform_device *pdev)
|
|||
regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF);
|
||||
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
|
||||
|
||||
data->cdev = cpufreq_cooling_register(cpu_present_mask);
|
||||
data->policy = cpufreq_cpu_get(0);
|
||||
if (!data->policy) {
|
||||
pr_debug("%s: CPUFreq policy not found\n", __func__);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
data->cdev = cpufreq_cooling_register(data->policy);
|
||||
if (IS_ERR(data->cdev)) {
|
||||
ret = PTR_ERR(data->cdev);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev,
|
||||
"failed to register cpufreq cooling device: %d\n",
|
||||
ret);
|
||||
"failed to register cpufreq cooling device: %d\n", ret);
|
||||
cpufreq_cpu_put(data->policy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -542,6 +549,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev,
|
||||
"failed to get thermal clk: %d\n", ret);
|
||||
cpufreq_cooling_unregister(data->cdev);
|
||||
cpufreq_cpu_put(data->policy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -556,6 +564,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
|
|||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
|
||||
cpufreq_cooling_unregister(data->cdev);
|
||||
cpufreq_cpu_put(data->policy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -571,6 +580,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
|
|||
"failed to register thermal zone device %d\n", ret);
|
||||
clk_disable_unprepare(data->thermal_clk);
|
||||
cpufreq_cooling_unregister(data->cdev);
|
||||
cpufreq_cpu_put(data->policy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -599,6 +609,7 @@ static int imx_thermal_probe(struct platform_device *pdev)
|
|||
clk_disable_unprepare(data->thermal_clk);
|
||||
thermal_zone_device_unregister(data->tz);
|
||||
cpufreq_cooling_unregister(data->cdev);
|
||||
cpufreq_cpu_put(data->policy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -620,6 +631,7 @@ static int imx_thermal_remove(struct platform_device *pdev)
|
|||
|
||||
thermal_zone_device_unregister(data->tz);
|
||||
cpufreq_cooling_unregister(data->cdev);
|
||||
cpufreq_cpu_put(data->policy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/cpu_cooling.h>
|
||||
#include <linux/of.h>
|
||||
|
@ -37,6 +38,7 @@
|
|||
|
||||
/* common data structures */
|
||||
struct ti_thermal_data {
|
||||
struct cpufreq_policy *policy;
|
||||
struct thermal_zone_device *ti_thermal;
|
||||
struct thermal_zone_device *pcb_tz;
|
||||
struct thermal_cooling_device *cool_dev;
|
||||
|
@ -247,15 +249,19 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
|
|||
if (!data)
|
||||
return -EINVAL;
|
||||
|
||||
data->policy = cpufreq_cpu_get(0);
|
||||
if (!data->policy) {
|
||||
pr_debug("%s: CPUFreq policy not found\n", __func__);
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
/* Register cooling device */
|
||||
data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
|
||||
data->cool_dev = cpufreq_cooling_register(data->policy);
|
||||
if (IS_ERR(data->cool_dev)) {
|
||||
int ret = PTR_ERR(data->cool_dev);
|
||||
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(bgp->dev,
|
||||
"Failed to register cpu cooling device %d\n",
|
||||
dev_err(bgp->dev, "Failed to register cpu cooling device %d\n",
|
||||
ret);
|
||||
cpufreq_cpu_put(data->policy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -270,8 +276,10 @@ int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
|
|||
|
||||
data = ti_bandgap_get_sensor_data(bgp, id);
|
||||
|
||||
if (data)
|
||||
if (data) {
|
||||
cpufreq_cooling_unregister(data->cool_dev);
|
||||
cpufreq_cpu_put(data->policy);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -28,47 +28,49 @@
|
|||
#include <linux/thermal.h>
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
struct cpufreq_policy;
|
||||
|
||||
typedef int (*get_static_t)(cpumask_t *cpumask, int interval,
|
||||
unsigned long voltage, u32 *power);
|
||||
|
||||
#ifdef CONFIG_CPU_THERMAL
|
||||
/**
|
||||
* cpufreq_cooling_register - function to create cpufreq cooling device.
|
||||
* @clip_cpus: cpumask of cpus where the frequency constraints will happen
|
||||
* @policy: cpufreq policy.
|
||||
*/
|
||||
struct thermal_cooling_device *
|
||||
cpufreq_cooling_register(const struct cpumask *clip_cpus);
|
||||
cpufreq_cooling_register(struct cpufreq_policy *policy);
|
||||
|
||||
struct thermal_cooling_device *
|
||||
cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
|
||||
cpufreq_power_cooling_register(struct cpufreq_policy *policy,
|
||||
u32 capacitance, get_static_t plat_static_func);
|
||||
|
||||
/**
|
||||
* of_cpufreq_cooling_register - create cpufreq cooling device based on DT.
|
||||
* @np: a valid struct device_node to the cooling device device tree node.
|
||||
* @clip_cpus: cpumask of cpus where the frequency constraints will happen
|
||||
* @policy: cpufreq policy.
|
||||
*/
|
||||
#ifdef CONFIG_THERMAL_OF
|
||||
struct thermal_cooling_device *
|
||||
of_cpufreq_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus);
|
||||
struct cpufreq_policy *policy);
|
||||
|
||||
struct thermal_cooling_device *
|
||||
of_cpufreq_power_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus,
|
||||
struct cpufreq_policy *policy,
|
||||
u32 capacitance,
|
||||
get_static_t plat_static_func);
|
||||
#else
|
||||
static inline struct thermal_cooling_device *
|
||||
of_cpufreq_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus)
|
||||
struct cpufreq_policy *policy)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline struct thermal_cooling_device *
|
||||
of_cpufreq_power_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus,
|
||||
struct cpufreq_policy *policy,
|
||||
u32 capacitance,
|
||||
get_static_t plat_static_func)
|
||||
{
|
||||
|
@ -84,12 +86,12 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
|
|||
|
||||
#else /* !CONFIG_CPU_THERMAL */
|
||||
static inline struct thermal_cooling_device *
|
||||
cpufreq_cooling_register(const struct cpumask *clip_cpus)
|
||||
cpufreq_cooling_register(struct cpufreq_policy *policy)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
static inline struct thermal_cooling_device *
|
||||
cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
|
||||
cpufreq_power_cooling_register(struct cpufreq_policy *policy,
|
||||
u32 capacitance, get_static_t plat_static_func)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -97,14 +99,14 @@ cpufreq_power_cooling_register(const struct cpumask *clip_cpus,
|
|||
|
||||
static inline struct thermal_cooling_device *
|
||||
of_cpufreq_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus)
|
||||
struct cpufreq_policy *policy)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
static inline struct thermal_cooling_device *
|
||||
of_cpufreq_power_cooling_register(struct device_node *np,
|
||||
const struct cpumask *clip_cpus,
|
||||
struct cpufreq_policy *policy,
|
||||
u32 capacitance,
|
||||
get_static_t plat_static_func)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue