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:
Родитель
6a1490367c
Коммит
5130802ddb
|
@ -16,6 +16,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpu.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()
|
||||
* @cpufreq_state: integer value representing the current state of cpufreq
|
||||
* 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
|
||||
* cpufreq frequencies.
|
||||
* @freq_table: Freq table in descending order of frequencies
|
||||
|
@ -84,12 +83,12 @@ struct cpufreq_cooling_device {
|
|||
int id;
|
||||
u32 last_load;
|
||||
unsigned int cpufreq_state;
|
||||
unsigned int clipped_freq;
|
||||
unsigned int max_level;
|
||||
struct freq_table *freq_table; /* In descending order */
|
||||
struct cpufreq_policy *policy;
|
||||
struct list_head node;
|
||||
struct time_in_idle *idle_time;
|
||||
struct dev_pm_qos_request qos_req;
|
||||
};
|
||||
|
||||
static DEFINE_IDA(cpufreq_ida);
|
||||
|
@ -118,59 +117,6 @@ static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_cdev,
|
|||
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
|
||||
* @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)
|
||||
{
|
||||
struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
|
||||
unsigned int clip_freq;
|
||||
|
||||
/* Request state should be less than 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)
|
||||
return 0;
|
||||
|
||||
clip_freq = cpufreq_cdev->freq_table[state].frequency;
|
||||
cpufreq_cdev->cpufreq_state = state;
|
||||
cpufreq_cdev->clipped_freq = clip_freq;
|
||||
|
||||
cpufreq_update_policy(cpufreq_cdev->policy->cpu);
|
||||
|
||||
return 0;
|
||||
return dev_pm_qos_update_request(&cpufreq_cdev->qos_req,
|
||||
cpufreq_cdev->freq_table[state].frequency);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -554,11 +496,6 @@ static struct thermal_cooling_device_ops cpufreq_power_cooling_ops = {
|
|||
.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,
|
||||
unsigned int prev_max)
|
||||
{
|
||||
|
@ -596,9 +533,16 @@ __cpufreq_cooling_register(struct device_node *np,
|
|||
struct cpufreq_cooling_device *cpufreq_cdev;
|
||||
char dev_name[THERMAL_NAME_LENGTH];
|
||||
unsigned int freq, i, num_cpus;
|
||||
struct device *dev;
|
||||
int ret;
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
cooling_ops);
|
||||
if (IS_ERR(cdev))
|
||||
goto remove_ida;
|
||||
|
||||
cpufreq_cdev->clipped_freq = cpufreq_cdev->freq_table[0].frequency;
|
||||
goto remove_qos_req;
|
||||
|
||||
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);
|
||||
mutex_unlock(&cooling_list_lock);
|
||||
|
||||
if (first)
|
||||
cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
|
||||
return cdev;
|
||||
|
||||
remove_qos_req:
|
||||
dev_pm_qos_remove_request(&cpufreq_cdev->qos_req);
|
||||
remove_ida:
|
||||
ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
|
||||
free_table:
|
||||
|
@ -777,7 +725,6 @@ EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
|
|||
void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
||||
{
|
||||
struct cpufreq_cooling_device *cpufreq_cdev;
|
||||
bool last;
|
||||
|
||||
if (!cdev)
|
||||
return;
|
||||
|
@ -786,15 +733,10 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
|||
|
||||
mutex_lock(&cooling_list_lock);
|
||||
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);
|
||||
|
||||
if (last)
|
||||
cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
|
||||
thermal_cooling_device_unregister(cdev);
|
||||
dev_pm_qos_remove_request(&cpufreq_cdev->qos_req);
|
||||
ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
|
||||
kfree(cpufreq_cdev->idle_time);
|
||||
kfree(cpufreq_cdev->freq_table);
|
||||
|
|
Загрузка…
Ссылка в новой задаче