Commit 5130802d authored by Viresh Kumar's avatar Viresh Kumar Committed by Rafael J. Wysocki

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: default avatarViresh Kumar <viresh.kumar@linaro.org>
[ rjw: Subject ]
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 6a149036
...@@ -16,6 +16,7 @@ ...@@ -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 { ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 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 = { ...@@ -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, ...@@ -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, ...@@ -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); ...@@ -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) ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment