Commit 992b9ff1 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'opp/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm

Pull operating performance points (OPP) changes for v5.12 from Viresh
Kumar:

"- Generic cleanups across the OPP core (Dmitry Osipenko, Viresh
   Kumar).

 - New OPP helpers dev_pm_opp_find_level_ceil(),
   dev_pm_opp_get_required_pstate(), dev_pm_opp_sync_regulators(),
   devm_pm_opp_register_set_opp_helper(),
   dev_pm_opp_of_add_table_noclk() and devm_pm_opp_attach_genpd()
   (Dmitry Osipenko, Viresh Kumar).

 - Allow required OPPs to be used for devfreq devices and related
   changes to devfreq governor (Saravana Kannan).

 - Significant code changes to allow a new OPP helper,
   dev_pm_opp_set_opp() (Viresh Kumar).

 - Remove dev_pm_opp_set_bw() and update related drivers (Viresh
   Kumar).

 - Allow lazy linking of required-OPPs (Viresh Kumar)."

* 'opp/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm: (37 commits)
  PM / devfreq: Add required OPPs support to passive governor
  PM / devfreq: Cache OPP table reference in devfreq
  OPP: Add function to look up required OPP's for a given OPP
  opp: Replace ENOTSUPP with EOPNOTSUPP
  opp: Fix "foo * bar" should be "foo *bar"
  opp: Don't ignore clk_get() errors other than -ENOENT
  opp: Update bandwidth requirements based on scaling up/down
  opp: Allow lazy-linking of required-opps
  opp: Remove dev_pm_opp_set_bw()
  devfreq: tegra30: Migrate to dev_pm_opp_set_opp()
  drm: msm: Migrate to dev_pm_opp_set_opp()
  cpufreq: qcom: Migrate to dev_pm_opp_set_opp()
  opp: Implement dev_pm_opp_set_opp()
  opp: Update parameters of  _set_opp_custom()
  opp: Allow _generic_set_opp_clk_only() to work for non-freq devices
  opp: Allow _generic_set_opp_regulator() to work for non-freq devices
  opp: Allow _set_opp() to work for non-freq devices
  opp: Split _set_opp() out of dev_pm_opp_set_rate()
  opp: Keep track of currently programmed OPP
  opp: No need to check clk for errors
  ...
parents 1048ba83 86ad9a24
...@@ -54,7 +54,7 @@ static int qcom_cpufreq_set_bw(struct cpufreq_policy *policy, ...@@ -54,7 +54,7 @@ static int qcom_cpufreq_set_bw(struct cpufreq_policy *policy,
if (IS_ERR(opp)) if (IS_ERR(opp))
return PTR_ERR(opp); return PTR_ERR(opp);
ret = dev_pm_opp_set_bw(dev, opp); ret = dev_pm_opp_set_opp(dev, opp);
dev_pm_opp_put(opp); dev_pm_opp_put(opp);
return ret; return ret;
} }
......
...@@ -757,6 +757,9 @@ static void devfreq_dev_release(struct device *dev) ...@@ -757,6 +757,9 @@ static void devfreq_dev_release(struct device *dev)
if (devfreq->profile->exit) if (devfreq->profile->exit)
devfreq->profile->exit(devfreq->dev.parent); devfreq->profile->exit(devfreq->dev.parent);
if (devfreq->opp_table)
dev_pm_opp_put_opp_table(devfreq->opp_table);
mutex_destroy(&devfreq->lock); mutex_destroy(&devfreq->lock);
kfree(devfreq); kfree(devfreq);
} }
...@@ -844,6 +847,10 @@ struct devfreq *devfreq_add_device(struct device *dev, ...@@ -844,6 +847,10 @@ struct devfreq *devfreq_add_device(struct device *dev,
} }
devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev); devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
devfreq->opp_table = dev_pm_opp_get_opp_table(dev);
if (IS_ERR(devfreq->opp_table))
devfreq->opp_table = NULL;
atomic_set(&devfreq->suspend_count, 0); atomic_set(&devfreq->suspend_count, 0);
dev_set_name(&devfreq->dev, "%s", dev_name(dev)); dev_set_name(&devfreq->dev, "%s", dev_name(dev));
......
...@@ -19,18 +19,16 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq, ...@@ -19,18 +19,16 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
= (struct devfreq_passive_data *)devfreq->data; = (struct devfreq_passive_data *)devfreq->data;
struct devfreq *parent_devfreq = (struct devfreq *)p_data->parent; struct devfreq *parent_devfreq = (struct devfreq *)p_data->parent;
unsigned long child_freq = ULONG_MAX; unsigned long child_freq = ULONG_MAX;
struct dev_pm_opp *opp; struct dev_pm_opp *opp, *p_opp;
int i, count, ret = 0; int i, count;
/* /*
* If the devfreq device with passive governor has the specific method * If the devfreq device with passive governor has the specific method
* to determine the next frequency, should use the get_target_freq() * to determine the next frequency, should use the get_target_freq()
* of struct devfreq_passive_data. * of struct devfreq_passive_data.
*/ */
if (p_data->get_target_freq) { if (p_data->get_target_freq)
ret = p_data->get_target_freq(devfreq, freq); return p_data->get_target_freq(devfreq, freq);
goto out;
}
/* /*
* If the parent and passive devfreq device uses the OPP table, * If the parent and passive devfreq device uses the OPP table,
...@@ -56,26 +54,35 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq, ...@@ -56,26 +54,35 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
* list of parent device. Because in this case, *freq is temporary * list of parent device. Because in this case, *freq is temporary
* value which is decided by ondemand governor. * value which is decided by ondemand governor.
*/ */
opp = devfreq_recommended_opp(parent_devfreq->dev.parent, freq, 0); if (devfreq->opp_table && parent_devfreq->opp_table) {
if (IS_ERR(opp)) { p_opp = devfreq_recommended_opp(parent_devfreq->dev.parent,
ret = PTR_ERR(opp); freq, 0);
goto out; if (IS_ERR(p_opp))
} return PTR_ERR(p_opp);
opp = dev_pm_opp_xlate_required_opp(parent_devfreq->opp_table,
devfreq->opp_table, p_opp);
dev_pm_opp_put(p_opp);
dev_pm_opp_put(opp); if (IS_ERR(opp))
return PTR_ERR(opp);
*freq = dev_pm_opp_get_freq(opp);
dev_pm_opp_put(opp);
return 0;
}
/* /*
* Get the OPP table's index of decided freqeuncy by governor * Get the OPP table's index of decided frequency by governor
* of parent device. * of parent device.
*/ */
for (i = 0; i < parent_devfreq->profile->max_state; i++) for (i = 0; i < parent_devfreq->profile->max_state; i++)
if (parent_devfreq->profile->freq_table[i] == *freq) if (parent_devfreq->profile->freq_table[i] == *freq)
break; break;
if (i == parent_devfreq->profile->max_state) { if (i == parent_devfreq->profile->max_state)
ret = -EINVAL; return -EINVAL;
goto out;
}
/* Get the suitable frequency by using index of parent device. */ /* Get the suitable frequency by using index of parent device. */
if (i < devfreq->profile->max_state) { if (i < devfreq->profile->max_state) {
...@@ -88,8 +95,7 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq, ...@@ -88,8 +95,7 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
/* Return the suitable frequency for passive device. */ /* Return the suitable frequency for passive device. */
*freq = child_freq; *freq = child_freq;
out: return 0;
return ret;
} }
static int devfreq_passive_notifier_call(struct notifier_block *nb, static int devfreq_passive_notifier_call(struct notifier_block *nb,
......
...@@ -647,7 +647,7 @@ static int tegra_devfreq_target(struct device *dev, unsigned long *freq, ...@@ -647,7 +647,7 @@ static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
return PTR_ERR(opp); return PTR_ERR(opp);
} }
ret = dev_pm_opp_set_bw(dev, opp); ret = dev_pm_opp_set_opp(dev, opp);
dev_pm_opp_put(opp); dev_pm_opp_put(opp);
return ret; return ret;
...@@ -849,7 +849,7 @@ static int tegra_devfreq_probe(struct platform_device *pdev) ...@@ -849,7 +849,7 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
return err; return err;
} }
err = dev_pm_opp_of_add_table(&pdev->dev); err = dev_pm_opp_of_add_table_noclk(&pdev->dev, 0);
if (err) { if (err) {
dev_err(&pdev->dev, "Failed to add OPP table: %d\n", err); dev_err(&pdev->dev, "Failed to add OPP table: %d\n", err);
goto put_hw; goto put_hw;
......
...@@ -134,7 +134,7 @@ void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp) ...@@ -134,7 +134,7 @@ void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp)
if (!gmu->legacy) { if (!gmu->legacy) {
a6xx_hfi_set_freq(gmu, perf_index); a6xx_hfi_set_freq(gmu, perf_index);
dev_pm_opp_set_bw(&gpu->pdev->dev, opp); dev_pm_opp_set_opp(&gpu->pdev->dev, opp);
pm_runtime_put(gmu->dev); pm_runtime_put(gmu->dev);
return; return;
} }
...@@ -158,7 +158,7 @@ void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp) ...@@ -158,7 +158,7 @@ void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp)
if (ret) if (ret)
dev_err(gmu->dev, "GMU set GPU frequency error: %d\n", ret); dev_err(gmu->dev, "GMU set GPU frequency error: %d\n", ret);
dev_pm_opp_set_bw(&gpu->pdev->dev, opp); dev_pm_opp_set_opp(&gpu->pdev->dev, opp);
pm_runtime_put(gmu->dev); pm_runtime_put(gmu->dev);
} }
...@@ -866,7 +866,7 @@ static void a6xx_gmu_set_initial_bw(struct msm_gpu *gpu, struct a6xx_gmu *gmu) ...@@ -866,7 +866,7 @@ static void a6xx_gmu_set_initial_bw(struct msm_gpu *gpu, struct a6xx_gmu *gmu)
if (IS_ERR_OR_NULL(gpu_opp)) if (IS_ERR_OR_NULL(gpu_opp))
return; return;
dev_pm_opp_set_bw(&gpu->pdev->dev, gpu_opp); dev_pm_opp_set_opp(&gpu->pdev->dev, gpu_opp);
dev_pm_opp_put(gpu_opp); dev_pm_opp_put(gpu_opp);
} }
...@@ -1072,7 +1072,7 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu) ...@@ -1072,7 +1072,7 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu)
a6xx_gmu_shutdown(gmu); a6xx_gmu_shutdown(gmu);
/* Remove the bus vote */ /* Remove the bus vote */
dev_pm_opp_set_bw(&gpu->pdev->dev, NULL); dev_pm_opp_set_opp(&gpu->pdev->dev, NULL);
/* /*
* Make sure the GX domain is off before turning off the GMU (CX) * Make sure the GX domain is off before turning off the GMU (CX)
......
This diff is collapsed.
This diff is collapsed.
...@@ -26,7 +26,7 @@ struct regulator; ...@@ -26,7 +26,7 @@ struct regulator;
/* Lock to allow exclusive modification to the device and opp lists */ /* Lock to allow exclusive modification to the device and opp lists */
extern struct mutex opp_table_lock; extern struct mutex opp_table_lock;
extern struct list_head opp_tables; extern struct list_head opp_tables, lazy_opp_tables;
/* /*
* Internal data structure organization with the OPP layer library is as * Internal data structure organization with the OPP layer library is as
...@@ -135,6 +135,7 @@ enum opp_table_access { ...@@ -135,6 +135,7 @@ enum opp_table_access {
* @clock_latency_ns_max: Max clock latency in nanoseconds. * @clock_latency_ns_max: Max clock latency in nanoseconds.
* @parsed_static_opps: Count of devices for which OPPs are initialized from DT. * @parsed_static_opps: Count of devices for which OPPs are initialized from DT.
* @shared_opp: OPP is shared between multiple devices. * @shared_opp: OPP is shared between multiple devices.
* @current_opp: Currently configured OPP for the table.
* @suspend_opp: Pointer to OPP to be used during device suspend. * @suspend_opp: Pointer to OPP to be used during device suspend.
* @genpd_virt_dev_lock: Mutex protecting the genpd virtual device pointers. * @genpd_virt_dev_lock: Mutex protecting the genpd virtual device pointers.
* @genpd_virt_devs: List of virtual devices for multiple genpd support. * @genpd_virt_devs: List of virtual devices for multiple genpd support.
...@@ -155,6 +156,7 @@ enum opp_table_access { ...@@ -155,6 +156,7 @@ enum opp_table_access {
* @genpd_performance_state: Device's power domain support performance state. * @genpd_performance_state: Device's power domain support performance state.
* @is_genpd: Marks if the OPP table belongs to a genpd. * @is_genpd: Marks if the OPP table belongs to a genpd.
* @set_opp: Platform specific set_opp callback * @set_opp: Platform specific set_opp callback
* @sod_supplies: Set opp data supplies
* @set_opp_data: Data to be passed to set_opp callback * @set_opp_data: Data to be passed to set_opp callback
* @dentry: debugfs dentry pointer of the real device directory (not links). * @dentry: debugfs dentry pointer of the real device directory (not links).
* @dentry_name: Name of the real dentry. * @dentry_name: Name of the real dentry.
...@@ -166,7 +168,7 @@ enum opp_table_access { ...@@ -166,7 +168,7 @@ enum opp_table_access {
* meant for book keeping and private to OPP library. * meant for book keeping and private to OPP library.
*/ */
struct opp_table { struct opp_table {
struct list_head node; struct list_head node, lazy;
struct blocking_notifier_head head; struct blocking_notifier_head head;
struct list_head dev_list; struct list_head dev_list;
...@@ -182,6 +184,7 @@ struct opp_table { ...@@ -182,6 +184,7 @@ struct opp_table {
unsigned int parsed_static_opps; unsigned int parsed_static_opps;
enum opp_table_access shared_opp; enum opp_table_access shared_opp;
struct dev_pm_opp *current_opp;
struct dev_pm_opp *suspend_opp; struct dev_pm_opp *suspend_opp;
struct mutex genpd_virt_dev_lock; struct mutex genpd_virt_dev_lock;
...@@ -202,6 +205,7 @@ struct opp_table { ...@@ -202,6 +205,7 @@ struct opp_table {
bool is_genpd; bool is_genpd;
int (*set_opp)(struct dev_pm_set_opp_data *data); int (*set_opp)(struct dev_pm_set_opp_data *data);
struct dev_pm_opp_supply *sod_supplies;
struct dev_pm_set_opp_data *set_opp_data; struct dev_pm_set_opp_data *set_opp_data;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
...@@ -223,9 +227,14 @@ int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2); ...@@ -223,9 +227,14 @@ int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2);
int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available); int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available);
int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic); int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic);
void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu); void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu);
struct opp_table *_add_opp_table(struct device *dev); struct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk);
struct opp_table *_add_opp_table_indexed(struct device *dev, int index);
void _put_opp_list_kref(struct opp_table *opp_table); void _put_opp_list_kref(struct opp_table *opp_table);
void _required_opps_available(struct dev_pm_opp *opp, int count);
static inline bool lazy_linking_pending(struct opp_table *opp_table)
{
return unlikely(!list_empty(&opp_table->lazy));
}
#ifdef CONFIG_OF #ifdef CONFIG_OF
void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index); void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index);
......
...@@ -137,6 +137,7 @@ struct devfreq_stats { ...@@ -137,6 +137,7 @@ struct devfreq_stats {
* using devfreq. * using devfreq.
* @profile: device-specific devfreq profile * @profile: device-specific devfreq profile
* @governor: method how to choose frequency based on the usage. * @governor: method how to choose frequency based on the usage.
* @opp_table: Reference to OPP table of dev.parent, if one exists.
* @nb: notifier block used to notify devfreq object that it should * @nb: notifier block used to notify devfreq object that it should
* reevaluate operable frequencies. Devfreq users may use * reevaluate operable frequencies. Devfreq users may use
* devfreq.nb to the corresponding register notifier call chain. * devfreq.nb to the corresponding register notifier call chain.
...@@ -173,6 +174,7 @@ struct devfreq { ...@@ -173,6 +174,7 @@ struct devfreq {
struct device dev; struct device dev;
struct devfreq_dev_profile *profile; struct devfreq_dev_profile *profile;
const struct devfreq_governor *governor; const struct devfreq_governor *governor;
struct opp_table *opp_table;
struct notifier_block nb; struct notifier_block nb;
struct delayed_work work; struct delayed_work work;
......
This diff is collapsed.
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