forked from Minki/linux
Merge branch 'pm-cpufreq'
* pm-cpufreq: cpufreq: Make cpufreq_generic_init() return void cpufreq: imx-cpufreq-dt: Add i.MX8MN support cpufreq: Add QoS requests for userspace constraints cpufreq: intel_pstate: Reuse refresh_frequency_limits() cpufreq: Register notifiers with the PM QoS framework PM / QoS: Add support for MIN/MAX frequency constraints PM / QOS: Pass request type to dev_pm_qos_read_value() PM / QOS: Rename __dev_pm_qos_read_value() and dev_pm_qos_raw_read_value() PM / QOS: Pass request type to dev_pm_qos_{add|remove}_notifier()
This commit is contained in:
commit
918e162e6a
@ -123,7 +123,7 @@ Will remove the element. After removal it will update the aggregate target and
|
||||
call the notification trees if the target was changed as a result of removing
|
||||
the request.
|
||||
|
||||
s32 dev_pm_qos_read_value(device):
|
||||
s32 dev_pm_qos_read_value(device, type):
|
||||
Returns the aggregated value for a given device's constraints list.
|
||||
|
||||
enum pm_qos_flags_status dev_pm_qos_flags(device, mask)
|
||||
@ -164,12 +164,14 @@ directory.
|
||||
Notification mechanisms:
|
||||
The per-device PM QoS framework has a per-device notification tree.
|
||||
|
||||
int dev_pm_qos_add_notifier(device, notifier):
|
||||
Adds a notification callback function for the device.
|
||||
The callback is called when the aggregated value of the device constraints list
|
||||
is changed (for resume latency device PM QoS only).
|
||||
int dev_pm_qos_add_notifier(device, notifier, type):
|
||||
Adds a notification callback function for the device for a particular request
|
||||
type.
|
||||
|
||||
int dev_pm_qos_remove_notifier(device, notifier):
|
||||
The callback is called when the aggregated value of the device constraints list
|
||||
is changed.
|
||||
|
||||
int dev_pm_qos_remove_notifier(device, notifier, type):
|
||||
Removes the notification callback function for the device.
|
||||
|
||||
|
||||
|
@ -1536,7 +1536,8 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
|
||||
if (ret)
|
||||
genpd_free_dev_data(dev, gpd_data);
|
||||
else
|
||||
dev_pm_qos_add_notifier(dev, &gpd_data->nb);
|
||||
dev_pm_qos_add_notifier(dev, &gpd_data->nb,
|
||||
DEV_PM_QOS_RESUME_LATENCY);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1569,7 +1570,8 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
|
||||
|
||||
pdd = dev->power.subsys_data->domain_data;
|
||||
gpd_data = to_gpd_data(pdd);
|
||||
dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
|
||||
dev_pm_qos_remove_notifier(dev, &gpd_data->nb,
|
||||
DEV_PM_QOS_RESUME_LATENCY);
|
||||
|
||||
genpd_lock(genpd);
|
||||
|
||||
@ -1597,7 +1599,7 @@ static int genpd_remove_device(struct generic_pm_domain *genpd,
|
||||
|
||||
out:
|
||||
genpd_unlock(genpd);
|
||||
dev_pm_qos_add_notifier(dev, &gpd_data->nb);
|
||||
dev_pm_qos_add_notifier(dev, &gpd_data->nb, DEV_PM_QOS_RESUME_LATENCY);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ static int dev_update_qos_constraint(struct device *dev, void *data)
|
||||
* take its current PM QoS constraint (that's the only thing
|
||||
* known at this point anyway).
|
||||
*/
|
||||
constraint_ns = dev_pm_qos_read_value(dev);
|
||||
constraint_ns = dev_pm_qos_read_value(dev, DEV_PM_QOS_RESUME_LATENCY);
|
||||
constraint_ns *= NSEC_PER_USEC;
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ static bool default_suspend_ok(struct device *dev)
|
||||
td->constraint_changed = false;
|
||||
td->cached_suspend_ok = false;
|
||||
td->effective_constraint_ns = 0;
|
||||
constraint_ns = __dev_pm_qos_read_value(dev);
|
||||
constraint_ns = __dev_pm_qos_resume_latency(dev);
|
||||
|
||||
spin_unlock_irqrestore(&dev->power.lock, flags);
|
||||
|
||||
|
@ -90,29 +90,49 @@ enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
|
||||
EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
|
||||
|
||||
/**
|
||||
* __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
|
||||
* __dev_pm_qos_resume_latency - Get resume latency constraint for a given device.
|
||||
* @dev: Device to get the PM QoS constraint value for.
|
||||
*
|
||||
* This routine must be called with dev->power.lock held.
|
||||
*/
|
||||
s32 __dev_pm_qos_read_value(struct device *dev)
|
||||
s32 __dev_pm_qos_resume_latency(struct device *dev)
|
||||
{
|
||||
lockdep_assert_held(&dev->power.lock);
|
||||
|
||||
return dev_pm_qos_raw_read_value(dev);
|
||||
return dev_pm_qos_raw_resume_latency(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
|
||||
* @dev: Device to get the PM QoS constraint value for.
|
||||
* @type: QoS request type.
|
||||
*/
|
||||
s32 dev_pm_qos_read_value(struct device *dev)
|
||||
s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
|
||||
{
|
||||
struct dev_pm_qos *qos = dev->power.qos;
|
||||
unsigned long flags;
|
||||
s32 ret;
|
||||
|
||||
spin_lock_irqsave(&dev->power.lock, flags);
|
||||
ret = __dev_pm_qos_read_value(dev);
|
||||
|
||||
switch (type) {
|
||||
case DEV_PM_QOS_RESUME_LATENCY:
|
||||
ret = IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT
|
||||
: pm_qos_read_value(&qos->resume_latency);
|
||||
break;
|
||||
case DEV_PM_QOS_MIN_FREQUENCY:
|
||||
ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE
|
||||
: pm_qos_read_value(&qos->min_frequency);
|
||||
break;
|
||||
case DEV_PM_QOS_MAX_FREQUENCY:
|
||||
ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE
|
||||
: pm_qos_read_value(&qos->max_frequency);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dev->power.lock, flags);
|
||||
|
||||
return ret;
|
||||
@ -149,6 +169,14 @@ static int apply_constraint(struct dev_pm_qos_request *req,
|
||||
req->dev->power.set_latency_tolerance(req->dev, value);
|
||||
}
|
||||
break;
|
||||
case DEV_PM_QOS_MIN_FREQUENCY:
|
||||
ret = pm_qos_update_target(&qos->min_frequency,
|
||||
&req->data.pnode, action, value);
|
||||
break;
|
||||
case DEV_PM_QOS_MAX_FREQUENCY:
|
||||
ret = pm_qos_update_target(&qos->max_frequency,
|
||||
&req->data.pnode, action, value);
|
||||
break;
|
||||
case DEV_PM_QOS_FLAGS:
|
||||
ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
|
||||
action, value);
|
||||
@ -177,12 +205,11 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
|
||||
if (!qos)
|
||||
return -ENOMEM;
|
||||
|
||||
n = kzalloc(sizeof(*n), GFP_KERNEL);
|
||||
n = kzalloc(3 * sizeof(*n), GFP_KERNEL);
|
||||
if (!n) {
|
||||
kfree(qos);
|
||||
return -ENOMEM;
|
||||
}
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(n);
|
||||
|
||||
c = &qos->resume_latency;
|
||||
plist_head_init(&c->list);
|
||||
@ -191,6 +218,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
|
||||
c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
|
||||
c->type = PM_QOS_MIN;
|
||||
c->notifiers = n;
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(n);
|
||||
|
||||
c = &qos->latency_tolerance;
|
||||
plist_head_init(&c->list);
|
||||
@ -199,6 +227,24 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
|
||||
c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
|
||||
c->type = PM_QOS_MIN;
|
||||
|
||||
c = &qos->min_frequency;
|
||||
plist_head_init(&c->list);
|
||||
c->target_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
|
||||
c->default_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
|
||||
c->no_constraint_value = PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
|
||||
c->type = PM_QOS_MAX;
|
||||
c->notifiers = ++n;
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(n);
|
||||
|
||||
c = &qos->max_frequency;
|
||||
plist_head_init(&c->list);
|
||||
c->target_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
|
||||
c->default_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
|
||||
c->no_constraint_value = PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
|
||||
c->type = PM_QOS_MIN;
|
||||
c->notifiers = ++n;
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(n);
|
||||
|
||||
INIT_LIST_HEAD(&qos->flags.list);
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
@ -252,11 +298,25 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
|
||||
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
|
||||
memset(req, 0, sizeof(*req));
|
||||
}
|
||||
|
||||
c = &qos->latency_tolerance;
|
||||
plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
|
||||
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
|
||||
memset(req, 0, sizeof(*req));
|
||||
}
|
||||
|
||||
c = &qos->min_frequency;
|
||||
plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
|
||||
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE);
|
||||
memset(req, 0, sizeof(*req));
|
||||
}
|
||||
|
||||
c = &qos->max_frequency;
|
||||
plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
|
||||
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
|
||||
memset(req, 0, sizeof(*req));
|
||||
}
|
||||
|
||||
f = &qos->flags;
|
||||
list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
|
||||
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
|
||||
@ -368,6 +428,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
|
||||
switch(req->type) {
|
||||
case DEV_PM_QOS_RESUME_LATENCY:
|
||||
case DEV_PM_QOS_LATENCY_TOLERANCE:
|
||||
case DEV_PM_QOS_MIN_FREQUENCY:
|
||||
case DEV_PM_QOS_MAX_FREQUENCY:
|
||||
curr_value = req->data.pnode.prio;
|
||||
break;
|
||||
case DEV_PM_QOS_FLAGS:
|
||||
@ -467,6 +529,7 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
|
||||
*
|
||||
* @dev: target device for the constraint
|
||||
* @notifier: notifier block managed by caller.
|
||||
* @type: request type.
|
||||
*
|
||||
* Will register the notifier into a notification chain that gets called
|
||||
* upon changes to the target value for the device.
|
||||
@ -474,7 +537,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
|
||||
* If the device's constraints object doesn't exist when this routine is called,
|
||||
* it will be created (or error code will be returned if that fails).
|
||||
*/
|
||||
int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
|
||||
int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
|
||||
enum dev_pm_qos_req_type type)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@ -485,10 +549,28 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
|
||||
else if (!dev->power.qos)
|
||||
ret = dev_pm_qos_constraints_allocate(dev);
|
||||
|
||||
if (!ret)
|
||||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
switch (type) {
|
||||
case DEV_PM_QOS_RESUME_LATENCY:
|
||||
ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
|
||||
notifier);
|
||||
break;
|
||||
case DEV_PM_QOS_MIN_FREQUENCY:
|
||||
ret = blocking_notifier_chain_register(dev->power.qos->min_frequency.notifiers,
|
||||
notifier);
|
||||
break;
|
||||
case DEV_PM_QOS_MAX_FREQUENCY:
|
||||
ret = blocking_notifier_chain_register(dev->power.qos->max_frequency.notifiers,
|
||||
notifier);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&dev_pm_qos_mtx);
|
||||
return ret;
|
||||
}
|
||||
@ -500,24 +582,44 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
|
||||
*
|
||||
* @dev: target device for the constraint
|
||||
* @notifier: notifier block to be removed.
|
||||
* @type: request type.
|
||||
*
|
||||
* Will remove the notifier from the notification chain that gets called
|
||||
* upon changes to the target value.
|
||||
*/
|
||||
int dev_pm_qos_remove_notifier(struct device *dev,
|
||||
struct notifier_block *notifier)
|
||||
struct notifier_block *notifier,
|
||||
enum dev_pm_qos_req_type type)
|
||||
{
|
||||
int retval = 0;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&dev_pm_qos_mtx);
|
||||
|
||||
/* Silently return if the constraints object is not present. */
|
||||
if (!IS_ERR_OR_NULL(dev->power.qos))
|
||||
retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
|
||||
notifier);
|
||||
if (IS_ERR_OR_NULL(dev->power.qos))
|
||||
goto unlock;
|
||||
|
||||
switch (type) {
|
||||
case DEV_PM_QOS_RESUME_LATENCY:
|
||||
ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
|
||||
notifier);
|
||||
break;
|
||||
case DEV_PM_QOS_MIN_FREQUENCY:
|
||||
ret = blocking_notifier_chain_unregister(dev->power.qos->min_frequency.notifiers,
|
||||
notifier);
|
||||
break;
|
||||
case DEV_PM_QOS_MAX_FREQUENCY:
|
||||
ret = blocking_notifier_chain_unregister(dev->power.qos->max_frequency.notifiers,
|
||||
notifier);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&dev_pm_qos_mtx);
|
||||
return retval;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
|
||||
|
||||
@ -577,6 +679,9 @@ static void __dev_pm_qos_drop_user_request(struct device *dev,
|
||||
req = dev->power.qos->flags_req;
|
||||
dev->power.qos->flags_req = NULL;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
__dev_pm_qos_remove_request(req);
|
||||
kfree(req);
|
||||
|
@ -275,7 +275,7 @@ static int rpm_check_suspend_allowed(struct device *dev)
|
||||
|| (dev->power.request_pending
|
||||
&& dev->power.request == RPM_REQ_RESUME))
|
||||
retval = -EAGAIN;
|
||||
else if (__dev_pm_qos_read_value(dev) == 0)
|
||||
else if (__dev_pm_qos_resume_latency(dev) == 0)
|
||||
retval = -EPERM;
|
||||
else if (dev->power.runtime_status == RPM_SUSPENDED)
|
||||
retval = 1;
|
||||
|
@ -131,23 +131,18 @@ static int bmips_cpufreq_exit(struct cpufreq_policy *policy)
|
||||
static int bmips_cpufreq_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpufreq_frequency_table *freq_table;
|
||||
int ret;
|
||||
|
||||
freq_table = bmips_cpufreq_get_freq_table(policy);
|
||||
if (IS_ERR(freq_table)) {
|
||||
ret = PTR_ERR(freq_table);
|
||||
pr_err("%s: couldn't determine frequency table (%d).\n",
|
||||
BMIPS_CPUFREQ_NAME, ret);
|
||||
return ret;
|
||||
pr_err("%s: couldn't determine frequency table (%ld).\n",
|
||||
BMIPS_CPUFREQ_NAME, PTR_ERR(freq_table));
|
||||
return PTR_ERR(freq_table);
|
||||
}
|
||||
|
||||
ret = cpufreq_generic_init(policy, freq_table, TRANSITION_LATENCY);
|
||||
if (ret)
|
||||
bmips_cpufreq_exit(policy);
|
||||
else
|
||||
cpufreq_generic_init(policy, freq_table, TRANSITION_LATENCY);
|
||||
pr_info("%s: registered\n", BMIPS_CPUFREQ_NAME);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver bmips_cpufreq_driver = {
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
@ -158,7 +159,7 @@ EXPORT_SYMBOL_GPL(arch_set_freq_scale);
|
||||
* - set policies transition latency
|
||||
* - policy->cpus with all possible CPUs
|
||||
*/
|
||||
int cpufreq_generic_init(struct cpufreq_policy *policy,
|
||||
void cpufreq_generic_init(struct cpufreq_policy *policy,
|
||||
struct cpufreq_frequency_table *table,
|
||||
unsigned int transition_latency)
|
||||
{
|
||||
@ -170,8 +171,6 @@ int cpufreq_generic_init(struct cpufreq_policy *policy,
|
||||
* share the clock and voltage and clock.
|
||||
*/
|
||||
cpumask_setall(policy->cpus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_generic_init);
|
||||
|
||||
@ -714,23 +713,15 @@ static ssize_t show_scaling_cur_freq(struct cpufreq_policy *policy, char *buf)
|
||||
static ssize_t store_##file_name \
|
||||
(struct cpufreq_policy *policy, const char *buf, size_t count) \
|
||||
{ \
|
||||
int ret, temp; \
|
||||
struct cpufreq_policy new_policy; \
|
||||
unsigned long val; \
|
||||
int ret; \
|
||||
\
|
||||
memcpy(&new_policy, policy, sizeof(*policy)); \
|
||||
new_policy.min = policy->user_policy.min; \
|
||||
new_policy.max = policy->user_policy.max; \
|
||||
\
|
||||
ret = sscanf(buf, "%u", &new_policy.object); \
|
||||
ret = sscanf(buf, "%lu", &val); \
|
||||
if (ret != 1) \
|
||||
return -EINVAL; \
|
||||
\
|
||||
temp = new_policy.object; \
|
||||
ret = cpufreq_set_policy(policy, &new_policy); \
|
||||
if (!ret) \
|
||||
policy->user_policy.object = temp; \
|
||||
\
|
||||
return ret ? ret : count; \
|
||||
ret = dev_pm_qos_update_request(policy->object##_freq_req, val);\
|
||||
return ret >= 0 ? count : ret; \
|
||||
}
|
||||
|
||||
store_one(scaling_min_freq, min);
|
||||
@ -996,7 +987,7 @@ static void add_cpu_dev_symlink(struct cpufreq_policy *policy, unsigned int cpu)
|
||||
{
|
||||
struct device *dev = get_cpu_device(cpu);
|
||||
|
||||
if (!dev)
|
||||
if (unlikely(!dev))
|
||||
return;
|
||||
|
||||
if (cpumask_test_and_set_cpu(cpu, policy->real_cpus))
|
||||
@ -1112,17 +1103,18 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, unsigned int cp
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void refresh_frequency_limits(struct cpufreq_policy *policy)
|
||||
void refresh_frequency_limits(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpufreq_policy new_policy = *policy;
|
||||
struct cpufreq_policy new_policy;
|
||||
|
||||
if (!policy_is_inactive(policy)) {
|
||||
new_policy = *policy;
|
||||
pr_debug("updating policy for CPU %u\n", policy->cpu);
|
||||
|
||||
new_policy.min = policy->user_policy.min;
|
||||
new_policy.max = policy->user_policy.max;
|
||||
|
||||
cpufreq_set_policy(policy, &new_policy);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(refresh_frequency_limits);
|
||||
|
||||
static void handle_update(struct work_struct *work)
|
||||
{
|
||||
@ -1130,60 +1122,27 @@ static void handle_update(struct work_struct *work)
|
||||
container_of(work, struct cpufreq_policy, update);
|
||||
|
||||
pr_debug("handle_update for cpu %u called\n", policy->cpu);
|
||||
down_write(&policy->rwsem);
|
||||
refresh_frequency_limits(policy);
|
||||
up_write(&policy->rwsem);
|
||||
}
|
||||
|
||||
static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
|
||||
static int cpufreq_notifier_min(struct notifier_block *nb, unsigned long freq,
|
||||
void *data)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
int ret;
|
||||
struct cpufreq_policy *policy = container_of(nb, struct cpufreq_policy, nb_min);
|
||||
|
||||
policy = kzalloc(sizeof(*policy), GFP_KERNEL);
|
||||
if (!policy)
|
||||
return NULL;
|
||||
|
||||
if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
|
||||
goto err_free_policy;
|
||||
|
||||
if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
|
||||
goto err_free_cpumask;
|
||||
|
||||
if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))
|
||||
goto err_free_rcpumask;
|
||||
|
||||
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
|
||||
cpufreq_global_kobject, "policy%u", cpu);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to init policy->kobj: %d\n", __func__, ret);
|
||||
/*
|
||||
* The entire policy object will be freed below, but the extra
|
||||
* memory allocated for the kobject name needs to be freed by
|
||||
* releasing the kobject.
|
||||
*/
|
||||
kobject_put(&policy->kobj);
|
||||
goto err_free_real_cpus;
|
||||
schedule_work(&policy->update);
|
||||
return 0;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&policy->policy_list);
|
||||
init_rwsem(&policy->rwsem);
|
||||
spin_lock_init(&policy->transition_lock);
|
||||
init_waitqueue_head(&policy->transition_wait);
|
||||
init_completion(&policy->kobj_unregister);
|
||||
INIT_WORK(&policy->update, handle_update);
|
||||
static int cpufreq_notifier_max(struct notifier_block *nb, unsigned long freq,
|
||||
void *data)
|
||||
{
|
||||
struct cpufreq_policy *policy = container_of(nb, struct cpufreq_policy, nb_max);
|
||||
|
||||
policy->cpu = cpu;
|
||||
return policy;
|
||||
|
||||
err_free_real_cpus:
|
||||
free_cpumask_var(policy->real_cpus);
|
||||
err_free_rcpumask:
|
||||
free_cpumask_var(policy->related_cpus);
|
||||
err_free_cpumask:
|
||||
free_cpumask_var(policy->cpus);
|
||||
err_free_policy:
|
||||
kfree(policy);
|
||||
|
||||
return NULL;
|
||||
schedule_work(&policy->update);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
|
||||
@ -1208,8 +1167,90 @@ static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy)
|
||||
pr_debug("wait complete\n");
|
||||
}
|
||||
|
||||
static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu)
|
||||
{
|
||||
struct cpufreq_policy *policy;
|
||||
struct device *dev = get_cpu_device(cpu);
|
||||
int ret;
|
||||
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
policy = kzalloc(sizeof(*policy), GFP_KERNEL);
|
||||
if (!policy)
|
||||
return NULL;
|
||||
|
||||
if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL))
|
||||
goto err_free_policy;
|
||||
|
||||
if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL))
|
||||
goto err_free_cpumask;
|
||||
|
||||
if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL))
|
||||
goto err_free_rcpumask;
|
||||
|
||||
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
|
||||
cpufreq_global_kobject, "policy%u", cpu);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: failed to init policy->kobj: %d\n", __func__, ret);
|
||||
/*
|
||||
* The entire policy object will be freed below, but the extra
|
||||
* memory allocated for the kobject name needs to be freed by
|
||||
* releasing the kobject.
|
||||
*/
|
||||
kobject_put(&policy->kobj);
|
||||
goto err_free_real_cpus;
|
||||
}
|
||||
|
||||
policy->nb_min.notifier_call = cpufreq_notifier_min;
|
||||
policy->nb_max.notifier_call = cpufreq_notifier_max;
|
||||
|
||||
ret = dev_pm_qos_add_notifier(dev, &policy->nb_min,
|
||||
DEV_PM_QOS_MIN_FREQUENCY);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register MIN QoS notifier: %d (%*pbl)\n",
|
||||
ret, cpumask_pr_args(policy->cpus));
|
||||
goto err_kobj_remove;
|
||||
}
|
||||
|
||||
ret = dev_pm_qos_add_notifier(dev, &policy->nb_max,
|
||||
DEV_PM_QOS_MAX_FREQUENCY);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register MAX QoS notifier: %d (%*pbl)\n",
|
||||
ret, cpumask_pr_args(policy->cpus));
|
||||
goto err_min_qos_notifier;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&policy->policy_list);
|
||||
init_rwsem(&policy->rwsem);
|
||||
spin_lock_init(&policy->transition_lock);
|
||||
init_waitqueue_head(&policy->transition_wait);
|
||||
init_completion(&policy->kobj_unregister);
|
||||
INIT_WORK(&policy->update, handle_update);
|
||||
|
||||
policy->cpu = cpu;
|
||||
return policy;
|
||||
|
||||
err_min_qos_notifier:
|
||||
dev_pm_qos_remove_notifier(dev, &policy->nb_min,
|
||||
DEV_PM_QOS_MIN_FREQUENCY);
|
||||
err_kobj_remove:
|
||||
cpufreq_policy_put_kobj(policy);
|
||||
err_free_real_cpus:
|
||||
free_cpumask_var(policy->real_cpus);
|
||||
err_free_rcpumask:
|
||||
free_cpumask_var(policy->related_cpus);
|
||||
err_free_cpumask:
|
||||
free_cpumask_var(policy->cpus);
|
||||
err_free_policy:
|
||||
kfree(policy);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cpufreq_policy_free(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct device *dev = get_cpu_device(policy->cpu);
|
||||
unsigned long flags;
|
||||
int cpu;
|
||||
|
||||
@ -1221,6 +1262,14 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
|
||||
per_cpu(cpufreq_cpu_data, cpu) = NULL;
|
||||
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
|
||||
dev_pm_qos_remove_notifier(dev, &policy->nb_max,
|
||||
DEV_PM_QOS_MAX_FREQUENCY);
|
||||
dev_pm_qos_remove_notifier(dev, &policy->nb_min,
|
||||
DEV_PM_QOS_MIN_FREQUENCY);
|
||||
dev_pm_qos_remove_request(policy->max_freq_req);
|
||||
dev_pm_qos_remove_request(policy->min_freq_req);
|
||||
kfree(policy->min_freq_req);
|
||||
|
||||
cpufreq_policy_put_kobj(policy);
|
||||
free_cpumask_var(policy->real_cpus);
|
||||
free_cpumask_var(policy->related_cpus);
|
||||
@ -1298,16 +1347,50 @@ static int cpufreq_online(unsigned int cpu)
|
||||
cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
|
||||
|
||||
if (new_policy) {
|
||||
policy->user_policy.min = policy->min;
|
||||
policy->user_policy.max = policy->max;
|
||||
struct device *dev = get_cpu_device(cpu);
|
||||
|
||||
for_each_cpu(j, policy->related_cpus) {
|
||||
per_cpu(cpufreq_cpu_data, j) = policy;
|
||||
add_cpu_dev_symlink(policy, j);
|
||||
}
|
||||
} else {
|
||||
policy->min = policy->user_policy.min;
|
||||
policy->max = policy->user_policy.max;
|
||||
|
||||
policy->min_freq_req = kzalloc(2 * sizeof(*policy->min_freq_req),
|
||||
GFP_KERNEL);
|
||||
if (!policy->min_freq_req)
|
||||
goto out_destroy_policy;
|
||||
|
||||
ret = dev_pm_qos_add_request(dev, policy->min_freq_req,
|
||||
DEV_PM_QOS_MIN_FREQUENCY,
|
||||
policy->min);
|
||||
if (ret < 0) {
|
||||
/*
|
||||
* So we don't call dev_pm_qos_remove_request() for an
|
||||
* uninitialized request.
|
||||
*/
|
||||
kfree(policy->min_freq_req);
|
||||
policy->min_freq_req = NULL;
|
||||
|
||||
dev_err(dev, "Failed to add min-freq constraint (%d)\n",
|
||||
ret);
|
||||
goto out_destroy_policy;
|
||||
}
|
||||
|
||||
/*
|
||||
* This must be initialized right here to avoid calling
|
||||
* dev_pm_qos_remove_request() on uninitialized request in case
|
||||
* of errors.
|
||||
*/
|
||||
policy->max_freq_req = policy->min_freq_req + 1;
|
||||
|
||||
ret = dev_pm_qos_add_request(dev, policy->max_freq_req,
|
||||
DEV_PM_QOS_MAX_FREQUENCY,
|
||||
policy->max);
|
||||
if (ret < 0) {
|
||||
policy->max_freq_req = NULL;
|
||||
dev_err(dev, "Failed to add max-freq constraint (%d)\n",
|
||||
ret);
|
||||
goto out_destroy_policy;
|
||||
}
|
||||
}
|
||||
|
||||
if (cpufreq_driver->get && has_target()) {
|
||||
@ -2280,6 +2363,7 @@ int cpufreq_set_policy(struct cpufreq_policy *policy,
|
||||
struct cpufreq_policy *new_policy)
|
||||
{
|
||||
struct cpufreq_governor *old_gov;
|
||||
struct device *cpu_dev = get_cpu_device(policy->cpu);
|
||||
int ret;
|
||||
|
||||
pr_debug("setting new policy for CPU %u: %u - %u kHz\n",
|
||||
@ -2288,17 +2372,21 @@ int cpufreq_set_policy(struct cpufreq_policy *policy,
|
||||
memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
|
||||
|
||||
/*
|
||||
* This check works well when we store new min/max freq attributes,
|
||||
* because new_policy is a copy of policy with one field updated.
|
||||
* PM QoS framework collects all the requests from users and provide us
|
||||
* the final aggregated value here.
|
||||
*/
|
||||
if (new_policy->min > new_policy->max)
|
||||
return -EINVAL;
|
||||
new_policy->min = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MIN_FREQUENCY);
|
||||
new_policy->max = dev_pm_qos_read_value(cpu_dev, DEV_PM_QOS_MAX_FREQUENCY);
|
||||
|
||||
/* verify the cpu speed can be set within this limit */
|
||||
ret = cpufreq_driver->verify(new_policy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The notifier-chain shall be removed once all the users of
|
||||
* CPUFREQ_ADJUST are moved to use the QoS framework.
|
||||
*/
|
||||
/* adjust if necessary - all reasons */
|
||||
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
|
||||
CPUFREQ_ADJUST, new_policy);
|
||||
@ -2377,10 +2465,9 @@ int cpufreq_set_policy(struct cpufreq_policy *policy,
|
||||
* @cpu: CPU to re-evaluate the policy for.
|
||||
*
|
||||
* Update the current frequency for the cpufreq policy of @cpu and use
|
||||
* cpufreq_set_policy() to re-apply the min and max limits saved in the
|
||||
* user_policy sub-structure of that policy, which triggers the evaluation
|
||||
* of policy notifiers and the cpufreq driver's ->verify() callback for the
|
||||
* policy in question, among other things.
|
||||
* cpufreq_set_policy() to re-apply the min and max limits, which triggers the
|
||||
* evaluation of policy notifiers and the cpufreq driver's ->verify() callback
|
||||
* for the policy in question, among other things.
|
||||
*/
|
||||
void cpufreq_update_policy(unsigned int cpu)
|
||||
{
|
||||
@ -2440,10 +2527,9 @@ static int cpufreq_boost_set_sw(int state)
|
||||
break;
|
||||
}
|
||||
|
||||
down_write(&policy->rwsem);
|
||||
policy->user_policy.max = policy->max;
|
||||
cpufreq_governor_limits(policy);
|
||||
up_write(&policy->rwsem);
|
||||
ret = dev_pm_qos_update_request(policy->max_freq_req, policy->max);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -90,7 +90,8 @@ static int davinci_cpu_init(struct cpufreq_policy *policy)
|
||||
* Setting the latency to 2000 us to accommodate addition of drivers
|
||||
* to pre/post change notification list.
|
||||
*/
|
||||
return cpufreq_generic_init(policy, freq_table, 2000 * 1000);
|
||||
cpufreq_generic_init(policy, freq_table, 2000 * 1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver davinci_driver = {
|
||||
|
@ -44,10 +44,11 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)
|
||||
* According to datasheet minimum speed grading is not supported for
|
||||
* consumer parts so clamp to 1 to avoid warning for "no OPPs"
|
||||
*
|
||||
* Applies to 8mq and 8mm.
|
||||
* Applies to i.MX8M series SoCs.
|
||||
*/
|
||||
if (mkt_segment == 0 && speed_grade == 0 && (
|
||||
of_machine_is_compatible("fsl,imx8mm") ||
|
||||
of_machine_is_compatible("fsl,imx8mn") ||
|
||||
of_machine_is_compatible("fsl,imx8mq")))
|
||||
speed_grade = 1;
|
||||
|
||||
|
@ -190,14 +190,12 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
|
||||
static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
int ret;
|
||||
|
||||
policy->clk = clks[ARM].clk;
|
||||
ret = cpufreq_generic_init(policy, freq_table, transition_latency);
|
||||
cpufreq_generic_init(policy, freq_table, transition_latency);
|
||||
policy->suspend_freq = max_freq;
|
||||
dev_pm_opp_of_register_em(policy->cpus);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver imx6q_cpufreq_driver = {
|
||||
|
@ -898,7 +898,6 @@ static void intel_pstate_update_policies(void)
|
||||
static void intel_pstate_update_max_freq(unsigned int cpu)
|
||||
{
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
|
||||
struct cpufreq_policy new_policy;
|
||||
struct cpudata *cpudata;
|
||||
|
||||
if (!policy)
|
||||
@ -908,11 +907,7 @@ static void intel_pstate_update_max_freq(unsigned int cpu)
|
||||
policy->cpuinfo.max_freq = global.turbo_disabled_mf ?
|
||||
cpudata->pstate.max_freq : cpudata->pstate.turbo_freq;
|
||||
|
||||
memcpy(&new_policy, policy, sizeof(*policy));
|
||||
new_policy.max = min(policy->user_policy.max, policy->cpuinfo.max_freq);
|
||||
new_policy.min = min(policy->user_policy.min, new_policy.max);
|
||||
|
||||
cpufreq_set_policy(policy, &new_policy);
|
||||
refresh_frequency_limits(policy);
|
||||
|
||||
cpufreq_cpu_release(policy);
|
||||
}
|
||||
|
@ -85,7 +85,8 @@ static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
|
||||
/* Module init and exit code */
|
||||
static int kirkwood_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
return cpufreq_generic_init(policy, kirkwood_freq_table, 5000);
|
||||
cpufreq_generic_init(policy, kirkwood_freq_table, 5000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver kirkwood_cpufreq_driver = {
|
||||
|
@ -81,7 +81,7 @@ static int ls1x_cpufreq_init(struct cpufreq_policy *policy)
|
||||
struct device *cpu_dev = get_cpu_device(policy->cpu);
|
||||
struct cpufreq_frequency_table *freq_tbl;
|
||||
unsigned int pll_freq, freq;
|
||||
int steps, i, ret;
|
||||
int steps, i;
|
||||
|
||||
pll_freq = clk_get_rate(cpufreq->pll_clk) / 1000;
|
||||
|
||||
@ -103,11 +103,9 @@ static int ls1x_cpufreq_init(struct cpufreq_policy *policy)
|
||||
freq_tbl[i].frequency = CPUFREQ_TABLE_END;
|
||||
|
||||
policy->clk = cpufreq->clk;
|
||||
ret = cpufreq_generic_init(policy, freq_tbl, 0);
|
||||
if (ret)
|
||||
kfree(freq_tbl);
|
||||
cpufreq_generic_init(policy, freq_tbl, 0);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ls1x_cpufreq_exit(struct cpufreq_policy *policy)
|
||||
|
@ -95,7 +95,8 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
}
|
||||
|
||||
policy->clk = cpuclk;
|
||||
return cpufreq_generic_init(policy, &loongson2_clockmod_table[0], 0);
|
||||
cpufreq_generic_init(policy, &loongson2_clockmod_table[0], 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loongson2_cpufreq_exit(struct cpufreq_policy *policy)
|
||||
|
@ -140,7 +140,8 @@ static unsigned int maple_cpufreq_get_speed(unsigned int cpu)
|
||||
|
||||
static int maple_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
return cpufreq_generic_init(policy, maple_cpu_freqs, 12000);
|
||||
cpufreq_generic_init(policy, maple_cpu_freqs, 12000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver maple_cpufreq_driver = {
|
||||
|
@ -122,23 +122,18 @@ static int omap_cpu_init(struct cpufreq_policy *policy)
|
||||
dev_err(mpu_dev,
|
||||
"%s: cpu%d: failed creating freq table[%d]\n",
|
||||
__func__, policy->cpu, result);
|
||||
goto fail;
|
||||
clk_put(policy->clk);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
atomic_inc_return(&freq_table_users);
|
||||
|
||||
/* FIXME: what's the actual transition time? */
|
||||
result = cpufreq_generic_init(policy, freq_table, 300 * 1000);
|
||||
if (!result) {
|
||||
cpufreq_generic_init(policy, freq_table, 300 * 1000);
|
||||
dev_pm_opp_of_register_em(policy->cpus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
freq_table_free();
|
||||
fail:
|
||||
clk_put(policy->clk);
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_cpu_exit(struct cpufreq_policy *policy)
|
||||
|
@ -196,7 +196,8 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
policy->cur = pas_freqs[cur_astate].frequency;
|
||||
ppc_proc_freq = policy->cur * 1000ul;
|
||||
|
||||
return cpufreq_generic_init(policy, pas_freqs, get_gizmo_latency());
|
||||
cpufreq_generic_init(policy, pas_freqs, get_gizmo_latency());
|
||||
return 0;
|
||||
|
||||
out_unmap_sdcpwr:
|
||||
iounmap(sdcpwr_mapbase);
|
||||
|
@ -372,7 +372,8 @@ static int pmac_cpufreq_target( struct cpufreq_policy *policy,
|
||||
|
||||
static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
return cpufreq_generic_init(policy, pmac_cpu_freqs, transition_latency);
|
||||
cpufreq_generic_init(policy, pmac_cpu_freqs, transition_latency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 read_gpio(struct device_node *np)
|
||||
|
@ -321,7 +321,8 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
|
||||
|
||||
static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
return cpufreq_generic_init(policy, g5_cpu_freqs, transition_latency);
|
||||
cpufreq_generic_init(policy, g5_cpu_freqs, transition_latency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver g5_cpufreq_driver = {
|
||||
|
@ -447,21 +447,16 @@ static int s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
|
||||
/* Datasheet says PLL stabalisation time must be at least 300us,
|
||||
* so but add some fudge. (reference in LOCKCON0 register description)
|
||||
*/
|
||||
ret = cpufreq_generic_init(policy, s3c_freq->freq_table,
|
||||
cpufreq_generic_init(policy, s3c_freq->freq_table,
|
||||
(500 * 1000) + s3c_freq->regulator_latency);
|
||||
if (ret)
|
||||
goto err_freq_table;
|
||||
|
||||
register_reboot_notifier(&s3c2416_cpufreq_reboot_notifier);
|
||||
|
||||
return 0;
|
||||
|
||||
err_freq_table:
|
||||
#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
|
||||
regulator_put(s3c_freq->vddarm);
|
||||
err_vddarm:
|
||||
#endif
|
||||
clk_put(s3c_freq->armclk);
|
||||
#endif
|
||||
err_armclk:
|
||||
clk_put(s3c_freq->hclk);
|
||||
err_hclk:
|
||||
|
@ -144,7 +144,6 @@ out:
|
||||
|
||||
static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
int ret;
|
||||
struct cpufreq_frequency_table *freq;
|
||||
|
||||
if (policy->cpu != 0)
|
||||
@ -165,8 +164,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
|
||||
#ifdef CONFIG_REGULATOR
|
||||
vddarm = regulator_get(NULL, "vddarm");
|
||||
if (IS_ERR(vddarm)) {
|
||||
ret = PTR_ERR(vddarm);
|
||||
pr_err("Failed to obtain VDDARM: %d\n", ret);
|
||||
pr_err("Failed to obtain VDDARM: %ld\n", PTR_ERR(vddarm));
|
||||
pr_err("Only frequency scaling available\n");
|
||||
vddarm = NULL;
|
||||
} else {
|
||||
@ -196,16 +194,9 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
|
||||
* the PLLs, which we don't currently) is ~300us worst case,
|
||||
* but add some fudge.
|
||||
*/
|
||||
ret = cpufreq_generic_init(policy, s3c64xx_freq_table,
|
||||
cpufreq_generic_init(policy, s3c64xx_freq_table,
|
||||
(500 * 1000) + regulator_latency);
|
||||
if (ret != 0) {
|
||||
pr_err("Failed to configure frequency table: %d\n",
|
||||
ret);
|
||||
regulator_put(vddarm);
|
||||
clk_put(policy->clk);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver s3c64xx_cpufreq_driver = {
|
||||
|
@ -541,7 +541,8 @@ static int s5pv210_cpu_init(struct cpufreq_policy *policy)
|
||||
s5pv210_dram_conf[1].freq = clk_get_rate(dmc1_clk);
|
||||
|
||||
policy->suspend_freq = SLEEP_FREQ;
|
||||
return cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
|
||||
cpufreq_generic_init(policy, s5pv210_freq_table, 40000);
|
||||
return 0;
|
||||
|
||||
out_dmc1:
|
||||
clk_put(dmc0_clk);
|
||||
|
@ -181,7 +181,8 @@ static int sa1100_target(struct cpufreq_policy *policy, unsigned int ppcr)
|
||||
|
||||
static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
return cpufreq_generic_init(policy, sa11x0_freq_table, 0);
|
||||
cpufreq_generic_init(policy, sa11x0_freq_table, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver sa1100_driver __refdata = {
|
||||
|
@ -303,7 +303,8 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr)
|
||||
|
||||
static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
return cpufreq_generic_init(policy, sa11x0_freq_table, 0);
|
||||
cpufreq_generic_init(policy, sa11x0_freq_table, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* sa1110_driver needs __refdata because it must remain after init registers
|
||||
|
@ -153,8 +153,9 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
|
||||
static int spear_cpufreq_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
policy->clk = spear_cpufreq.clk;
|
||||
return cpufreq_generic_init(policy, spear_cpufreq.freq_tbl,
|
||||
cpufreq_generic_init(policy, spear_cpufreq.freq_tbl,
|
||||
spear_cpufreq.transition_latency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver spear_cpufreq_driver = {
|
||||
|
@ -118,17 +118,11 @@ static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
static int tegra_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct tegra20_cpufreq *cpufreq = cpufreq_get_driver_data();
|
||||
int ret;
|
||||
|
||||
clk_prepare_enable(cpufreq->cpu_clk);
|
||||
|
||||
/* FIXME: what's the actual transition time? */
|
||||
ret = cpufreq_generic_init(policy, freq_table, 300 * 1000);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(cpufreq->cpu_clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cpufreq_generic_init(policy, freq_table, 300 * 1000);
|
||||
policy->clk = cpufreq->cpu_clk;
|
||||
policy->suspend_freq = freq_table[0].frequency;
|
||||
return 0;
|
||||
|
@ -110,7 +110,7 @@ int cpuidle_governor_latency_req(unsigned int cpu)
|
||||
{
|
||||
int global_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
|
||||
struct device *device = get_cpu_device(cpu);
|
||||
int device_req = dev_pm_qos_raw_read_value(device);
|
||||
int device_req = dev_pm_qos_raw_resume_latency(device);
|
||||
|
||||
return device_req < global_req ? device_req : global_req;
|
||||
}
|
||||
|
@ -47,11 +47,6 @@ struct cpufreq_cpuinfo {
|
||||
unsigned int transition_latency;
|
||||
};
|
||||
|
||||
struct cpufreq_user_policy {
|
||||
unsigned int min; /* in kHz */
|
||||
unsigned int max; /* in kHz */
|
||||
};
|
||||
|
||||
struct cpufreq_policy {
|
||||
/* CPUs sharing clock, require sw coordination */
|
||||
cpumask_var_t cpus; /* Online CPUs only */
|
||||
@ -81,7 +76,8 @@ struct cpufreq_policy {
|
||||
struct work_struct update; /* if update_policy() needs to be
|
||||
* called, but you're in IRQ context */
|
||||
|
||||
struct cpufreq_user_policy user_policy;
|
||||
struct dev_pm_qos_request *min_freq_req;
|
||||
struct dev_pm_qos_request *max_freq_req;
|
||||
struct cpufreq_frequency_table *freq_table;
|
||||
enum cpufreq_table_sorting freq_table_sorted;
|
||||
|
||||
@ -144,6 +140,9 @@ struct cpufreq_policy {
|
||||
|
||||
/* Pointer to the cooling device if used for thermal mitigation */
|
||||
struct thermal_cooling_device *cdev;
|
||||
|
||||
struct notifier_block nb_min;
|
||||
struct notifier_block nb_max;
|
||||
};
|
||||
|
||||
struct cpufreq_freqs {
|
||||
@ -201,6 +200,7 @@ void cpufreq_cpu_release(struct cpufreq_policy *policy);
|
||||
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
|
||||
int cpufreq_set_policy(struct cpufreq_policy *policy,
|
||||
struct cpufreq_policy *new_policy);
|
||||
void refresh_frequency_limits(struct cpufreq_policy *policy);
|
||||
void cpufreq_update_policy(unsigned int cpu);
|
||||
void cpufreq_update_limits(unsigned int cpu);
|
||||
bool have_governor_per_policy(void);
|
||||
@ -992,7 +992,7 @@ extern struct freq_attr *cpufreq_generic_attr[];
|
||||
int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy);
|
||||
|
||||
unsigned int cpufreq_generic_get(unsigned int cpu);
|
||||
int cpufreq_generic_init(struct cpufreq_policy *policy,
|
||||
void cpufreq_generic_init(struct cpufreq_policy *policy,
|
||||
struct cpufreq_frequency_table *table,
|
||||
unsigned int transition_latency);
|
||||
#endif /* _LINUX_CPUFREQ_H */
|
||||
|
@ -40,6 +40,8 @@ enum pm_qos_flags_status {
|
||||
#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT PM_QOS_LATENCY_ANY
|
||||
#define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS PM_QOS_LATENCY_ANY_NS
|
||||
#define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0
|
||||
#define PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE 0
|
||||
#define PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE (-1)
|
||||
#define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1)
|
||||
|
||||
#define PM_QOS_FLAG_NO_POWER_OFF (1 << 0)
|
||||
@ -58,6 +60,8 @@ struct pm_qos_flags_request {
|
||||
enum dev_pm_qos_req_type {
|
||||
DEV_PM_QOS_RESUME_LATENCY = 1,
|
||||
DEV_PM_QOS_LATENCY_TOLERANCE,
|
||||
DEV_PM_QOS_MIN_FREQUENCY,
|
||||
DEV_PM_QOS_MAX_FREQUENCY,
|
||||
DEV_PM_QOS_FLAGS,
|
||||
};
|
||||
|
||||
@ -99,10 +103,14 @@ struct pm_qos_flags {
|
||||
struct dev_pm_qos {
|
||||
struct pm_qos_constraints resume_latency;
|
||||
struct pm_qos_constraints latency_tolerance;
|
||||
struct pm_qos_constraints min_frequency;
|
||||
struct pm_qos_constraints max_frequency;
|
||||
struct pm_qos_flags flags;
|
||||
struct dev_pm_qos_request *resume_latency_req;
|
||||
struct dev_pm_qos_request *latency_tolerance_req;
|
||||
struct dev_pm_qos_request *flags_req;
|
||||
struct dev_pm_qos_request *min_frequency_req;
|
||||
struct dev_pm_qos_request *max_frequency_req;
|
||||
};
|
||||
|
||||
/* Action requested to pm_qos_update_target */
|
||||
@ -139,16 +147,18 @@ s32 pm_qos_read_value(struct pm_qos_constraints *c);
|
||||
#ifdef CONFIG_PM
|
||||
enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask);
|
||||
enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask);
|
||||
s32 __dev_pm_qos_read_value(struct device *dev);
|
||||
s32 dev_pm_qos_read_value(struct device *dev);
|
||||
s32 __dev_pm_qos_resume_latency(struct device *dev);
|
||||
s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type);
|
||||
int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
|
||||
enum dev_pm_qos_req_type type, s32 value);
|
||||
int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value);
|
||||
int dev_pm_qos_remove_request(struct dev_pm_qos_request *req);
|
||||
int dev_pm_qos_add_notifier(struct device *dev,
|
||||
struct notifier_block *notifier);
|
||||
struct notifier_block *notifier,
|
||||
enum dev_pm_qos_req_type type);
|
||||
int dev_pm_qos_remove_notifier(struct device *dev,
|
||||
struct notifier_block *notifier);
|
||||
struct notifier_block *notifier,
|
||||
enum dev_pm_qos_req_type type);
|
||||
void dev_pm_qos_constraints_init(struct device *dev);
|
||||
void dev_pm_qos_constraints_destroy(struct device *dev);
|
||||
int dev_pm_qos_add_ancestor_request(struct device *dev,
|
||||
@ -174,7 +184,7 @@ static inline s32 dev_pm_qos_requested_flags(struct device *dev)
|
||||
return dev->power.qos->flags_req->data.flr.flags;
|
||||
}
|
||||
|
||||
static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
|
||||
static inline s32 dev_pm_qos_raw_resume_latency(struct device *dev)
|
||||
{
|
||||
return IS_ERR_OR_NULL(dev->power.qos) ?
|
||||
PM_QOS_RESUME_LATENCY_NO_CONSTRAINT :
|
||||
@ -187,10 +197,24 @@ static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
|
||||
static inline enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev,
|
||||
s32 mask)
|
||||
{ return PM_QOS_FLAGS_UNDEFINED; }
|
||||
static inline s32 __dev_pm_qos_read_value(struct device *dev)
|
||||
{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
|
||||
static inline s32 dev_pm_qos_read_value(struct device *dev)
|
||||
static inline s32 __dev_pm_qos_resume_latency(struct device *dev)
|
||||
{ return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT; }
|
||||
static inline s32 dev_pm_qos_read_value(struct device *dev,
|
||||
enum dev_pm_qos_req_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case DEV_PM_QOS_RESUME_LATENCY:
|
||||
return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
|
||||
case DEV_PM_QOS_MIN_FREQUENCY:
|
||||
return PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
|
||||
case DEV_PM_QOS_MAX_FREQUENCY:
|
||||
return PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int dev_pm_qos_add_request(struct device *dev,
|
||||
struct dev_pm_qos_request *req,
|
||||
enum dev_pm_qos_req_type type,
|
||||
@ -202,10 +226,12 @@ static inline int dev_pm_qos_update_request(struct dev_pm_qos_request *req,
|
||||
static inline int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
|
||||
{ return 0; }
|
||||
static inline int dev_pm_qos_add_notifier(struct device *dev,
|
||||
struct notifier_block *notifier)
|
||||
struct notifier_block *notifier,
|
||||
enum dev_pm_qos_req_type type)
|
||||
{ return 0; }
|
||||
static inline int dev_pm_qos_remove_notifier(struct device *dev,
|
||||
struct notifier_block *notifier)
|
||||
struct notifier_block *notifier,
|
||||
enum dev_pm_qos_req_type type)
|
||||
{ return 0; }
|
||||
static inline void dev_pm_qos_constraints_init(struct device *dev)
|
||||
{
|
||||
@ -241,7 +267,7 @@ static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
|
||||
return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
|
||||
}
|
||||
static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; }
|
||||
static inline s32 dev_pm_qos_raw_read_value(struct device *dev)
|
||||
static inline s32 dev_pm_qos_raw_resume_latency(struct device *dev)
|
||||
{
|
||||
return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user