PM / devfreq: Add support for policy notifiers

Change-Id: I6feff0c15d8685db91c8780ce90c4b31925f5abe
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
This commit is contained in:
Finley Xiao 2019-03-25 20:08:51 +08:00 committed by Tao Huang
parent 2f756f615c
commit 458874cea1
2 changed files with 70 additions and 6 deletions

View File

@ -252,6 +252,7 @@ static int devfreq_notify_transition(struct devfreq *devfreq,
*/
int update_devfreq(struct devfreq *devfreq)
{
struct devfreq_policy *policy = &devfreq->policy;
struct devfreq_freqs freqs;
unsigned long freq, cur_freq, min_freq, max_freq;
int err = 0;
@ -265,6 +266,11 @@ int update_devfreq(struct devfreq *devfreq)
if (!devfreq->governor)
return -EINVAL;
policy->max = devfreq->scaling_max_freq;
policy->min = devfreq->scaling_min_freq;
srcu_notifier_call_chain(&devfreq->policy_notifier_list, DEVFREQ_ADJUST,
policy);
/* Reevaluate the proper frequency */
err = devfreq->governor->get_target_freq(devfreq, &freq);
if (err)
@ -277,8 +283,8 @@ int update_devfreq(struct devfreq *devfreq)
* max_freq
* min_freq
*/
max_freq = min(devfreq->scaling_max_freq, devfreq->max_freq);
min_freq = max(devfreq->scaling_min_freq, devfreq->min_freq);
max_freq = min(policy->max, devfreq->max_freq);
min_freq = max(policy->min, devfreq->min_freq);
if (freq < min_freq) {
freq = min_freq;
@ -608,6 +614,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
goto err_dev;
}
devfreq->min_freq = devfreq->scaling_min_freq;
devfreq->policy.min = devfreq->min_freq;
devfreq->scaling_max_freq = find_available_max_freq(devfreq);
if (!devfreq->scaling_max_freq) {
@ -616,6 +623,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
goto err_dev;
}
devfreq->max_freq = devfreq->scaling_max_freq;
devfreq->policy.max = devfreq->max_freq;
dev_set_name(&devfreq->dev, "devfreq%d",
atomic_inc_return(&devfreq_no));
@ -639,6 +647,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
devfreq->last_stat_updated = jiffies;
srcu_init_notifier_head(&devfreq->transition_notifier_list);
srcu_init_notifier_head(&devfreq->policy_notifier_list);
mutex_unlock(&devfreq->lock);
@ -1158,7 +1167,7 @@ static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
{
struct devfreq *df = to_devfreq(dev);
return sprintf(buf, "%lu\n", max(df->scaling_min_freq, df->min_freq));
return sprintf(buf, "%lu\n", max(df->policy.min, df->min_freq));
}
static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
@ -1203,7 +1212,7 @@ static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
{
struct devfreq *df = to_devfreq(dev);
return sprintf(buf, "%lu\n", min(df->scaling_max_freq, df->max_freq));
return sprintf(buf, "%lu\n", min(df->policy.max, df->max_freq));
}
static DEVICE_ATTR_RW(max_freq);
@ -1432,7 +1441,7 @@ EXPORT_SYMBOL(devm_devfreq_unregister_opp_notifier);
* devfreq_register_notifier() - Register a driver with devfreq
* @devfreq: The devfreq object.
* @nb: The notifier block to register.
* @list: DEVFREQ_TRANSITION_NOTIFIER.
* @list: DEVFREQ_TRANSITION_NOTIFIER or DEVFREQ_POLICY_NOTIFIER.
*/
int devfreq_register_notifier(struct devfreq *devfreq,
struct notifier_block *nb,
@ -1448,6 +1457,10 @@ int devfreq_register_notifier(struct devfreq *devfreq,
ret = srcu_notifier_chain_register(
&devfreq->transition_notifier_list, nb);
break;
case DEVFREQ_POLICY_NOTIFIER:
ret = srcu_notifier_chain_register(
&devfreq->policy_notifier_list, nb);
break;
default:
ret = -EINVAL;
}
@ -1460,7 +1473,7 @@ EXPORT_SYMBOL(devfreq_register_notifier);
* devfreq_unregister_notifier() - Unregister a driver with devfreq
* @devfreq: The devfreq object.
* @nb: The notifier block to be unregistered.
* @list: DEVFREQ_TRANSITION_NOTIFIER.
* @list: DEVFREQ_TRANSITION_NOTIFIER or DEVFREQ_POLICY_NOTIFIER.
*/
int devfreq_unregister_notifier(struct devfreq *devfreq,
struct notifier_block *nb,
@ -1476,6 +1489,10 @@ int devfreq_unregister_notifier(struct devfreq *devfreq,
ret = srcu_notifier_chain_unregister(
&devfreq->transition_notifier_list, nb);
break;
case DEVFREQ_POLICY_NOTIFIER:
ret = srcu_notifier_chain_unregister(
&devfreq->policy_notifier_list, nb);
break;
default:
ret = -EINVAL;
}

View File

@ -28,11 +28,15 @@
/* DEVFREQ notifier interface */
#define DEVFREQ_TRANSITION_NOTIFIER (0)
#define DEVFREQ_POLICY_NOTIFIER (1)
/* Transition notifiers of DEVFREQ_TRANSITION_NOTIFIER */
#define DEVFREQ_PRECHANGE (0)
#define DEVFREQ_POSTCHANGE (1)
/* Policy Notifiers */
#define DEVFREQ_ADJUST (0)
struct devfreq;
struct devfreq_governor;
@ -109,6 +113,16 @@ struct devfreq_dev_profile {
unsigned int max_state;
};
/**
* struct devfreq_policy - Devfreq frequency limits
* @min_: minimum frequency (adjustable by policy notifiers)
* @max: maximum frequency (adjustable by policy notifiers)
*/
struct devfreq_policy {
unsigned long min;
unsigned long max;
};
/**
* struct devfreq - Device devfreq structure
* @node: list node - contains the devices with devfreq that have been
@ -126,6 +140,7 @@ struct devfreq_dev_profile {
* @previous_freq: previously configured frequency value.
* @data: Private data of the governor. The devfreq framework does not
* touch this.
* @policy: Frequency limits of the device
* @min_freq: Limit minimum frequency requested by user (0: none)
* @max_freq: Limit maximum frequency requested by user (0: none)
* @scaling_min_freq: Limit minimum frequency requested by OPP interface
@ -136,6 +151,7 @@ struct devfreq_dev_profile {
* @time_in_state: Statistics of devfreq states
* @last_stat_updated: The last time stat updated
* @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
* @policy_notifier_list: list head of DEVFREQ_POLICY_NOTIFIER notifier
*
* This structure stores the devfreq information for a give device.
*
@ -161,6 +177,8 @@ struct devfreq {
void *data; /* private data for governors */
struct devfreq_policy policy;
unsigned long min_freq;
unsigned long max_freq;
unsigned long scaling_min_freq;
@ -174,6 +192,7 @@ struct devfreq {
unsigned long last_stat_updated;
struct srcu_notifier_head transition_notifier_list;
struct srcu_notifier_head policy_notifier_list;
};
struct devfreq_freqs {
@ -226,6 +245,29 @@ extern void devm_devfreq_unregister_notifier(struct device *dev,
extern struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev,
int index);
/**
* devfreq_verify_within_limits() - Adjust a devfreq policy if needed to make
* sure its min/max values are within a
* specified range.
* @policy: the policy
* @min: the minimum frequency
* @max: the maximum frequency
*/
static inline void devfreq_verify_within_limits(struct devfreq_policy *policy,
unsigned int min, unsigned int max)
{
if (policy->min < min)
policy->min = min;
if (policy->max < min)
policy->max = min;
if (policy->min > max)
policy->min = max;
if (policy->max > max)
policy->max = max;
if (policy->min > policy->max)
policy->min = policy->max;
}
#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
/**
* struct devfreq_simple_ondemand_data - void *data fed to struct devfreq
@ -380,6 +422,11 @@ static inline struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev,
return ERR_PTR(-ENODEV);
}
static inline void devfreq_verify_within_limits(struct devfreq_policy *policy,
unsigned int min, unsigned int max)
{
}
static inline int devfreq_update_stats(struct devfreq *df)
{
return -EINVAL;