Merge branch 'for-rafael' of https://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq into pm-devfreq
Pull devfreq updates for v4.3 from MyungJoo Ham. * 'for-rafael' of https://git.kernel.org/pub/scm/linux/kernel/git/mzx/devfreq: PM / devfreq: Fix incorrect type issue. PM / devfreq: tegra: Update governor to use devfreq_update_stats() PM / devfreq: comments for get_dev_status usage updated PM / devfreq: drop comment about thermal setting max_freq PM / devfreq: cache the last call to get_dev_status() PM / devfreq: Drop unlikely before IS_ERR(_OR_NULL) PM / devfreq: exynos-ppmu: bit-wise operation bugfix. PM / devfreq: exynos-ppmu: Update documentation to support PPMUv2 PM / devfreq: exynos-ppmu: Add the support of PPMUv2 for Exynos5433 PM / devfreq: event: Remove incorrect property in exynos-ppmu DT binding Conflicts: drivers/devfreq/event/exynos-ppmu.c
This commit is contained in:
commit
4184a8fc57
|
@ -53,7 +53,7 @@ static struct devfreq *find_device_devfreq(struct device *dev)
|
||||||
{
|
{
|
||||||
struct devfreq *tmp_devfreq;
|
struct devfreq *tmp_devfreq;
|
||||||
|
|
||||||
if (unlikely(IS_ERR_OR_NULL(dev))) {
|
if (IS_ERR_OR_NULL(dev)) {
|
||||||
pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
|
pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ static struct devfreq_governor *find_devfreq_governor(const char *name)
|
||||||
{
|
{
|
||||||
struct devfreq_governor *tmp_governor;
|
struct devfreq_governor *tmp_governor;
|
||||||
|
|
||||||
if (unlikely(IS_ERR_OR_NULL(name))) {
|
if (IS_ERR_OR_NULL(name)) {
|
||||||
pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
|
pr_err("DEVFREQ: %s: Invalid parameters\n", __func__);
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
@ -177,10 +177,10 @@ int update_devfreq(struct devfreq *devfreq)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adjust the freuqency with user freq and QoS.
|
* Adjust the frequency with user freq and QoS.
|
||||||
*
|
*
|
||||||
* List from the highest proiority
|
* List from the highest priority
|
||||||
* max_freq (probably called by thermal when it's too hot)
|
* max_freq
|
||||||
* min_freq
|
* min_freq
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -482,7 +482,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
|
||||||
devfreq->profile->max_state *
|
devfreq->profile->max_state *
|
||||||
devfreq->profile->max_state,
|
devfreq->profile->max_state,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
devfreq->time_in_state = devm_kzalloc(dev, sizeof(unsigned int) *
|
devfreq->time_in_state = devm_kzalloc(dev, sizeof(unsigned long) *
|
||||||
devfreq->profile->max_state,
|
devfreq->profile->max_state,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
devfreq->last_stat_updated = jiffies;
|
devfreq->last_stat_updated = jiffies;
|
||||||
|
|
|
@ -319,7 +319,8 @@ static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev,
|
||||||
case PPMU_PMNCNT3:
|
case PPMU_PMNCNT3:
|
||||||
pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH);
|
pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH);
|
||||||
pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW);
|
pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW);
|
||||||
load_count = (u64)((pmcnt_high & 0xff) << 32) + (u64)pmcnt_low;
|
load_count = ((u64)((pmcnt_high & 0xff)) << 32)
|
||||||
|
+ (u64)pmcnt_low;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
edata->load_count = load_count;
|
edata->load_count = load_count;
|
||||||
|
|
|
@ -21,17 +21,20 @@
|
||||||
static int devfreq_simple_ondemand_func(struct devfreq *df,
|
static int devfreq_simple_ondemand_func(struct devfreq *df,
|
||||||
unsigned long *freq)
|
unsigned long *freq)
|
||||||
{
|
{
|
||||||
struct devfreq_dev_status stat;
|
int err;
|
||||||
int err = df->profile->get_dev_status(df->dev.parent, &stat);
|
struct devfreq_dev_status *stat;
|
||||||
unsigned long long a, b;
|
unsigned long long a, b;
|
||||||
unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD;
|
unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD;
|
||||||
unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;
|
unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL;
|
||||||
struct devfreq_simple_ondemand_data *data = df->data;
|
struct devfreq_simple_ondemand_data *data = df->data;
|
||||||
unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX;
|
unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX;
|
||||||
|
|
||||||
|
err = devfreq_update_stats(df);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
stat = &df->last_status;
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
if (data->upthreshold)
|
if (data->upthreshold)
|
||||||
dfso_upthreshold = data->upthreshold;
|
dfso_upthreshold = data->upthreshold;
|
||||||
|
@ -43,41 +46,41 @@ static int devfreq_simple_ondemand_func(struct devfreq *df,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* Assume MAX if it is going to be divided by zero */
|
/* Assume MAX if it is going to be divided by zero */
|
||||||
if (stat.total_time == 0) {
|
if (stat->total_time == 0) {
|
||||||
*freq = max;
|
*freq = max;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prevent overflow */
|
/* Prevent overflow */
|
||||||
if (stat.busy_time >= (1 << 24) || stat.total_time >= (1 << 24)) {
|
if (stat->busy_time >= (1 << 24) || stat->total_time >= (1 << 24)) {
|
||||||
stat.busy_time >>= 7;
|
stat->busy_time >>= 7;
|
||||||
stat.total_time >>= 7;
|
stat->total_time >>= 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set MAX if it's busy enough */
|
/* Set MAX if it's busy enough */
|
||||||
if (stat.busy_time * 100 >
|
if (stat->busy_time * 100 >
|
||||||
stat.total_time * dfso_upthreshold) {
|
stat->total_time * dfso_upthreshold) {
|
||||||
*freq = max;
|
*freq = max;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set MAX if we do not know the initial frequency */
|
/* Set MAX if we do not know the initial frequency */
|
||||||
if (stat.current_frequency == 0) {
|
if (stat->current_frequency == 0) {
|
||||||
*freq = max;
|
*freq = max;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep the current frequency */
|
/* Keep the current frequency */
|
||||||
if (stat.busy_time * 100 >
|
if (stat->busy_time * 100 >
|
||||||
stat.total_time * (dfso_upthreshold - dfso_downdifferential)) {
|
stat->total_time * (dfso_upthreshold - dfso_downdifferential)) {
|
||||||
*freq = stat.current_frequency;
|
*freq = stat->current_frequency;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the desired frequency based on the load */
|
/* Set the desired frequency based on the load */
|
||||||
a = stat.busy_time;
|
a = stat->busy_time;
|
||||||
a *= stat.current_frequency;
|
a *= stat->current_frequency;
|
||||||
b = div_u64(a, stat.total_time);
|
b = div_u64(a, stat->total_time);
|
||||||
b *= 100;
|
b *= 100;
|
||||||
b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2));
|
b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2));
|
||||||
*freq = (unsigned long) b;
|
*freq = (unsigned long) b;
|
||||||
|
|
|
@ -541,18 +541,20 @@ static struct devfreq_dev_profile tegra_devfreq_profile = {
|
||||||
static int tegra_governor_get_target(struct devfreq *devfreq,
|
static int tegra_governor_get_target(struct devfreq *devfreq,
|
||||||
unsigned long *freq)
|
unsigned long *freq)
|
||||||
{
|
{
|
||||||
struct devfreq_dev_status stat;
|
struct devfreq_dev_status *stat;
|
||||||
struct tegra_devfreq *tegra;
|
struct tegra_devfreq *tegra;
|
||||||
struct tegra_devfreq_device *dev;
|
struct tegra_devfreq_device *dev;
|
||||||
unsigned long target_freq = 0;
|
unsigned long target_freq = 0;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = devfreq->profile->get_dev_status(devfreq->dev.parent, &stat);
|
err = devfreq_update_stats(devfreq);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
tegra = stat.private_data;
|
stat = &devfreq->last_status;
|
||||||
|
|
||||||
|
tegra = stat->private_data;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
|
for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
|
||||||
dev = &tegra->devices[i];
|
dev = &tegra->devices[i];
|
||||||
|
|
|
@ -65,7 +65,10 @@ struct devfreq_dev_status {
|
||||||
* The "flags" parameter's possible values are
|
* The "flags" parameter's possible values are
|
||||||
* explained above with "DEVFREQ_FLAG_*" macros.
|
* explained above with "DEVFREQ_FLAG_*" macros.
|
||||||
* @get_dev_status: The device should provide the current performance
|
* @get_dev_status: The device should provide the current performance
|
||||||
* status to devfreq, which is used by governors.
|
* status to devfreq. Governors are recommended not to
|
||||||
|
* use this directly. Instead, governors are recommended
|
||||||
|
* to use devfreq_update_stats() along with
|
||||||
|
* devfreq.last_status.
|
||||||
* @get_cur_freq: The device should provide the current frequency
|
* @get_cur_freq: The device should provide the current frequency
|
||||||
* at which it is operating.
|
* at which it is operating.
|
||||||
* @exit: An optional callback that is called when devfreq
|
* @exit: An optional callback that is called when devfreq
|
||||||
|
@ -161,6 +164,7 @@ struct devfreq {
|
||||||
struct delayed_work work;
|
struct delayed_work work;
|
||||||
|
|
||||||
unsigned long previous_freq;
|
unsigned long previous_freq;
|
||||||
|
struct devfreq_dev_status last_status;
|
||||||
|
|
||||||
void *data; /* private data for governors */
|
void *data; /* private data for governors */
|
||||||
|
|
||||||
|
@ -204,6 +208,19 @@ extern int devm_devfreq_register_opp_notifier(struct device *dev,
|
||||||
extern void devm_devfreq_unregister_opp_notifier(struct device *dev,
|
extern void devm_devfreq_unregister_opp_notifier(struct device *dev,
|
||||||
struct devfreq *devfreq);
|
struct devfreq *devfreq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* devfreq_update_stats() - update the last_status pointer in struct devfreq
|
||||||
|
* @df: the devfreq instance whose status needs updating
|
||||||
|
*
|
||||||
|
* Governors are recommended to use this function along with last_status,
|
||||||
|
* which allows other entities to reuse the last_status without affecting
|
||||||
|
* the values fetched later by governors.
|
||||||
|
*/
|
||||||
|
static inline int devfreq_update_stats(struct devfreq *df)
|
||||||
|
{
|
||||||
|
return df->profile->get_dev_status(df->dev.parent, &df->last_status);
|
||||||
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
|
#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
|
||||||
/**
|
/**
|
||||||
* struct devfreq_simple_ondemand_data - void *data fed to struct devfreq
|
* struct devfreq_simple_ondemand_data - void *data fed to struct devfreq
|
||||||
|
@ -289,6 +306,11 @@ static inline void devm_devfreq_unregister_opp_notifier(struct device *dev,
|
||||||
struct devfreq *devfreq)
|
struct devfreq *devfreq)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int devfreq_update_stats(struct devfreq *df)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
#endif /* CONFIG_PM_DEVFREQ */
|
#endif /* CONFIG_PM_DEVFREQ */
|
||||||
|
|
||||||
#endif /* __LINUX_DEVFREQ_H__ */
|
#endif /* __LINUX_DEVFREQ_H__ */
|
||||||
|
|
Loading…
Reference in New Issue