mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-23 12:43:55 +08:00
thermal: cpu_cooling: Switch to QoS requests for freq limits
The cpufreq core now takes the min/max frequency constraints via QoS requests and the CPUFREQ_ADJUST notifier shall get removed later on. Switch over to using the QoS request for maximum frequency constraint for cpu_cooling driver. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> [ rjw: Subject ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
6a1490367c
commit
5130802ddb
@ -16,6 +16,7 @@
|
|||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/idr.h>
|
#include <linux/idr.h>
|
||||||
#include <linux/pm_opp.h>
|
#include <linux/pm_opp.h>
|
||||||
|
#include <linux/pm_qos.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
#include <linux/cpu_cooling.h>
|
#include <linux/cpu_cooling.h>
|
||||||
@ -66,8 +67,6 @@ struct time_in_idle {
|
|||||||
* @last_load: load measured by the latest call to cpufreq_get_requested_power()
|
* @last_load: load measured by the latest call to cpufreq_get_requested_power()
|
||||||
* @cpufreq_state: integer value representing the current state of cpufreq
|
* @cpufreq_state: integer value representing the current state of cpufreq
|
||||||
* cooling devices.
|
* cooling devices.
|
||||||
* @clipped_freq: integer value representing the absolute value of the clipped
|
|
||||||
* frequency.
|
|
||||||
* @max_level: maximum cooling level. One less than total number of valid
|
* @max_level: maximum cooling level. One less than total number of valid
|
||||||
* cpufreq frequencies.
|
* cpufreq frequencies.
|
||||||
* @freq_table: Freq table in descending order of frequencies
|
* @freq_table: Freq table in descending order of frequencies
|
||||||
@ -84,12 +83,12 @@ struct cpufreq_cooling_device {
|
|||||||
int id;
|
int id;
|
||||||
u32 last_load;
|
u32 last_load;
|
||||||
unsigned int cpufreq_state;
|
unsigned int cpufreq_state;
|
||||||
unsigned int clipped_freq;
|
|
||||||
unsigned int max_level;
|
unsigned int max_level;
|
||||||
struct freq_table *freq_table; /* In descending order */
|
struct freq_table *freq_table; /* In descending order */
|
||||||
struct cpufreq_policy *policy;
|
struct cpufreq_policy *policy;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
struct time_in_idle *idle_time;
|
struct time_in_idle *idle_time;
|
||||||
|
struct dev_pm_qos_request qos_req;
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFINE_IDA(cpufreq_ida);
|
static DEFINE_IDA(cpufreq_ida);
|
||||||
@ -118,59 +117,6 @@ static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_cdev,
|
|||||||
return level - 1;
|
return level - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* cpufreq_thermal_notifier - notifier callback for cpufreq policy change.
|
|
||||||
* @nb: struct notifier_block * with callback info.
|
|
||||||
* @event: value showing cpufreq event for which this function invoked.
|
|
||||||
* @data: callback-specific data
|
|
||||||
*
|
|
||||||
* Callback to hijack the notification on cpufreq policy transition.
|
|
||||||
* Every time there is a change in policy, we will intercept and
|
|
||||||
* update the cpufreq policy with thermal constraints.
|
|
||||||
*
|
|
||||||
* Return: 0 (success)
|
|
||||||
*/
|
|
||||||
static int cpufreq_thermal_notifier(struct notifier_block *nb,
|
|
||||||
unsigned long event, void *data)
|
|
||||||
{
|
|
||||||
struct cpufreq_policy *policy = data;
|
|
||||||
unsigned long clipped_freq;
|
|
||||||
struct cpufreq_cooling_device *cpufreq_cdev;
|
|
||||||
|
|
||||||
if (event != CPUFREQ_ADJUST)
|
|
||||||
return NOTIFY_DONE;
|
|
||||||
|
|
||||||
mutex_lock(&cooling_list_lock);
|
|
||||||
list_for_each_entry(cpufreq_cdev, &cpufreq_cdev_list, node) {
|
|
||||||
/*
|
|
||||||
* A new copy of the policy is sent to the notifier and can't
|
|
||||||
* compare that directly.
|
|
||||||
*/
|
|
||||||
if (policy->cpu != cpufreq_cdev->policy->cpu)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* policy->max is the maximum allowed frequency defined by user
|
|
||||||
* and clipped_freq is the maximum that thermal constraints
|
|
||||||
* allow.
|
|
||||||
*
|
|
||||||
* If clipped_freq is lower than policy->max, then we need to
|
|
||||||
* readjust policy->max.
|
|
||||||
*
|
|
||||||
* But, if clipped_freq is greater than policy->max, we don't
|
|
||||||
* need to do anything.
|
|
||||||
*/
|
|
||||||
clipped_freq = cpufreq_cdev->clipped_freq;
|
|
||||||
|
|
||||||
if (policy->max > clipped_freq)
|
|
||||||
cpufreq_verify_within_limits(policy, 0, clipped_freq);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
mutex_unlock(&cooling_list_lock);
|
|
||||||
|
|
||||||
return NOTIFY_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* update_freq_table() - Update the freq table with power numbers
|
* update_freq_table() - Update the freq table with power numbers
|
||||||
* @cpufreq_cdev: the cpufreq cooling device in which to update the table
|
* @cpufreq_cdev: the cpufreq cooling device in which to update the table
|
||||||
@ -374,7 +320,6 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
|
|||||||
unsigned long state)
|
unsigned long state)
|
||||||
{
|
{
|
||||||
struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
|
struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
|
||||||
unsigned int clip_freq;
|
|
||||||
|
|
||||||
/* Request state should be less than max_level */
|
/* Request state should be less than max_level */
|
||||||
if (WARN_ON(state > cpufreq_cdev->max_level))
|
if (WARN_ON(state > cpufreq_cdev->max_level))
|
||||||
@ -384,13 +329,10 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
|
|||||||
if (cpufreq_cdev->cpufreq_state == state)
|
if (cpufreq_cdev->cpufreq_state == state)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
clip_freq = cpufreq_cdev->freq_table[state].frequency;
|
|
||||||
cpufreq_cdev->cpufreq_state = state;
|
cpufreq_cdev->cpufreq_state = state;
|
||||||
cpufreq_cdev->clipped_freq = clip_freq;
|
|
||||||
|
|
||||||
cpufreq_update_policy(cpufreq_cdev->policy->cpu);
|
return dev_pm_qos_update_request(&cpufreq_cdev->qos_req,
|
||||||
|
cpufreq_cdev->freq_table[state].frequency);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -554,11 +496,6 @@ static struct thermal_cooling_device_ops cpufreq_power_cooling_ops = {
|
|||||||
.power2state = cpufreq_power2state,
|
.power2state = cpufreq_power2state,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Notifier for cpufreq policy change */
|
|
||||||
static struct notifier_block thermal_cpufreq_notifier_block = {
|
|
||||||
.notifier_call = cpufreq_thermal_notifier,
|
|
||||||
};
|
|
||||||
|
|
||||||
static unsigned int find_next_max(struct cpufreq_frequency_table *table,
|
static unsigned int find_next_max(struct cpufreq_frequency_table *table,
|
||||||
unsigned int prev_max)
|
unsigned int prev_max)
|
||||||
{
|
{
|
||||||
@ -596,9 +533,16 @@ __cpufreq_cooling_register(struct device_node *np,
|
|||||||
struct cpufreq_cooling_device *cpufreq_cdev;
|
struct cpufreq_cooling_device *cpufreq_cdev;
|
||||||
char dev_name[THERMAL_NAME_LENGTH];
|
char dev_name[THERMAL_NAME_LENGTH];
|
||||||
unsigned int freq, i, num_cpus;
|
unsigned int freq, i, num_cpus;
|
||||||
|
struct device *dev;
|
||||||
int ret;
|
int ret;
|
||||||
struct thermal_cooling_device_ops *cooling_ops;
|
struct thermal_cooling_device_ops *cooling_ops;
|
||||||
bool first;
|
|
||||||
|
dev = get_cpu_device(policy->cpu);
|
||||||
|
if (unlikely(!dev)) {
|
||||||
|
pr_warn("No cpu device for cpu %d\n", policy->cpu);
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (IS_ERR_OR_NULL(policy)) {
|
if (IS_ERR_OR_NULL(policy)) {
|
||||||
pr_err("%s: cpufreq policy isn't valid: %p\n", __func__, policy);
|
pr_err("%s: cpufreq policy isn't valid: %p\n", __func__, policy);
|
||||||
@ -671,25 +615,29 @@ __cpufreq_cooling_register(struct device_node *np,
|
|||||||
cooling_ops = &cpufreq_cooling_ops;
|
cooling_ops = &cpufreq_cooling_ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = dev_pm_qos_add_request(dev, &cpufreq_cdev->qos_req,
|
||||||
|
DEV_PM_QOS_MAX_FREQUENCY,
|
||||||
|
cpufreq_cdev->freq_table[0].frequency);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("%s: Failed to add freq constraint (%d)\n", __func__,
|
||||||
|
ret);
|
||||||
|
cdev = ERR_PTR(ret);
|
||||||
|
goto remove_ida;
|
||||||
|
}
|
||||||
|
|
||||||
cdev = thermal_of_cooling_device_register(np, dev_name, cpufreq_cdev,
|
cdev = thermal_of_cooling_device_register(np, dev_name, cpufreq_cdev,
|
||||||
cooling_ops);
|
cooling_ops);
|
||||||
if (IS_ERR(cdev))
|
if (IS_ERR(cdev))
|
||||||
goto remove_ida;
|
goto remove_qos_req;
|
||||||
|
|
||||||
cpufreq_cdev->clipped_freq = cpufreq_cdev->freq_table[0].frequency;
|
|
||||||
|
|
||||||
mutex_lock(&cooling_list_lock);
|
mutex_lock(&cooling_list_lock);
|
||||||
/* Register the notifier for first cpufreq cooling device */
|
|
||||||
first = list_empty(&cpufreq_cdev_list);
|
|
||||||
list_add(&cpufreq_cdev->node, &cpufreq_cdev_list);
|
list_add(&cpufreq_cdev->node, &cpufreq_cdev_list);
|
||||||
mutex_unlock(&cooling_list_lock);
|
mutex_unlock(&cooling_list_lock);
|
||||||
|
|
||||||
if (first)
|
|
||||||
cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
|
|
||||||
CPUFREQ_POLICY_NOTIFIER);
|
|
||||||
|
|
||||||
return cdev;
|
return cdev;
|
||||||
|
|
||||||
|
remove_qos_req:
|
||||||
|
dev_pm_qos_remove_request(&cpufreq_cdev->qos_req);
|
||||||
remove_ida:
|
remove_ida:
|
||||||
ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
|
ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
|
||||||
free_table:
|
free_table:
|
||||||
@ -777,7 +725,6 @@ EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
|
|||||||
void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||||
{
|
{
|
||||||
struct cpufreq_cooling_device *cpufreq_cdev;
|
struct cpufreq_cooling_device *cpufreq_cdev;
|
||||||
bool last;
|
|
||||||
|
|
||||||
if (!cdev)
|
if (!cdev)
|
||||||
return;
|
return;
|
||||||
@ -786,15 +733,10 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
|||||||
|
|
||||||
mutex_lock(&cooling_list_lock);
|
mutex_lock(&cooling_list_lock);
|
||||||
list_del(&cpufreq_cdev->node);
|
list_del(&cpufreq_cdev->node);
|
||||||
/* Unregister the notifier for the last cpufreq cooling device */
|
|
||||||
last = list_empty(&cpufreq_cdev_list);
|
|
||||||
mutex_unlock(&cooling_list_lock);
|
mutex_unlock(&cooling_list_lock);
|
||||||
|
|
||||||
if (last)
|
|
||||||
cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
|
|
||||||
CPUFREQ_POLICY_NOTIFIER);
|
|
||||||
|
|
||||||
thermal_cooling_device_unregister(cdev);
|
thermal_cooling_device_unregister(cdev);
|
||||||
|
dev_pm_qos_remove_request(&cpufreq_cdev->qos_req);
|
||||||
ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
|
ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
|
||||||
kfree(cpufreq_cdev->idle_time);
|
kfree(cpufreq_cdev->idle_time);
|
||||||
kfree(cpufreq_cdev->freq_table);
|
kfree(cpufreq_cdev->freq_table);
|
||||||
|
Loading…
Reference in New Issue
Block a user