Commit 7dc1d36e authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branches 'pm-cpufreq' and 'pm-devfreq'

* pm-cpufreq:
  cpufreq: acpi-cpufreq: Use cpufreq_cpu_get_raw() in ->get()

* pm-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
...@@ -375,12 +375,11 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu) ...@@ -375,12 +375,11 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
pr_debug("get_cur_freq_on_cpu (%d)\n", cpu); pr_debug("get_cur_freq_on_cpu (%d)\n", cpu);
policy = cpufreq_cpu_get(cpu); policy = cpufreq_cpu_get_raw(cpu);
if (unlikely(!policy)) if (unlikely(!policy))
return 0; return 0;
data = policy->driver_data; data = policy->driver_data;
cpufreq_cpu_put(policy);
if (unlikely(!data || !data->freq_table)) if (unlikely(!data || !data->freq_table))
return 0; return 0;
......
...@@ -238,13 +238,13 @@ int cpufreq_generic_init(struct cpufreq_policy *policy, ...@@ -238,13 +238,13 @@ int cpufreq_generic_init(struct cpufreq_policy *policy,
} }
EXPORT_SYMBOL_GPL(cpufreq_generic_init); EXPORT_SYMBOL_GPL(cpufreq_generic_init);
/* Only for cpufreq core internal use */ struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
static struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
{ {
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
return policy && cpumask_test_cpu(cpu, policy->cpus) ? policy : NULL; return policy && cpumask_test_cpu(cpu, policy->cpus) ? policy : NULL;
} }
EXPORT_SYMBOL_GPL(cpufreq_cpu_get_raw);
unsigned int cpufreq_generic_get(unsigned int cpu) unsigned int cpufreq_generic_get(unsigned int cpu)
{ {
......
...@@ -53,7 +53,7 @@ static struct devfreq *find_device_devfreq(struct device *dev) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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, ...@@ -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 = { ...@@ -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];
......
...@@ -127,9 +127,14 @@ struct cpufreq_policy { ...@@ -127,9 +127,14 @@ struct cpufreq_policy {
#define CPUFREQ_SHARED_TYPE_ANY (3) /* Freq can be set from any dependent CPU*/ #define CPUFREQ_SHARED_TYPE_ANY (3) /* Freq can be set from any dependent CPU*/
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu);
struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu); struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu);
void cpufreq_cpu_put(struct cpufreq_policy *policy); void cpufreq_cpu_put(struct cpufreq_policy *policy);
#else #else
static inline struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu)
{
return NULL;
}
static inline struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) static inline struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
{ {
return NULL; return NULL;
......
...@@ -65,7 +65,10 @@ struct devfreq_dev_status { ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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__ */
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