Message ID | 1557997725-12178-7-git-send-email-andrew-sh.cheng@mediatek.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add cpufreq and cci devfreq for mt8183, and SVS support | expand |
On 16-05-19, 17:08, Andrew-sh.Cheng wrote: > From: Stephen Boyd <sboyd@codeaurora.org> > > On some SoCs the Adaptive Voltage Scaling (AVS) technique is > employed to optimize the operating voltage of a device. At a > given frequency, the hardware monitors dynamic factors and either > makes a suggestion for how much to adjust a voltage for the > current frequency, or it automatically adjusts the voltage > without software intervention. Add an API to the OPP library for > the former case, so that AVS type devices can update the voltages > for an OPP when the hardware determines the voltage should > change. The assumption is that drivers like CPUfreq or devfreq > will register for the OPP notifiers and adjust the voltage > according to suggestions that AVS makes. > > This patch is devired from [1] submitted by Stephen. > [1] https://lore.kernel.org/patchwork/patch/599279/ > > Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> > Signed-off-by: Roger Lu <roger.lu@mediatek.com> > --- > drivers/opp/core.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ > include/linux/pm_opp.h | 11 +++++++ > 2 files changed, 89 insertions(+) This is an rcu implementation which got removed long back from OPP core. Please align this with the latest changes.
Dear Stephen Boyd, This patch is derived from [1]. Please kindly shares the suggestion to us. Thanks very much. [1]: https://lore.kernel.org/patchwork/patch/599279/ Dear Viresh, I followed _opp_set_availability() coding style to refine dev_pm_opp_adjust_voltage() from this patch. Is this refinement suitable for OPP core? Thanks a lot. On Mon, 2019-05-20 at 12:47 +0800, Viresh Kumar wrote: > On 16-05-19, 17:08, Andrew-sh.Cheng wrote: > > From: Stephen Boyd <sboyd@codeaurora.org> > > > > On some SoCs the Adaptive Voltage Scaling (AVS) technique is > > employed to optimize the operating voltage of a device. At a > > given frequency, the hardware monitors dynamic factors and either > > makes a suggestion for how much to adjust a voltage for the > > current frequency, or it automatically adjusts the voltage > > without software intervention. Add an API to the OPP library for > > the former case, so that AVS type devices can update the voltages > > for an OPP when the hardware determines the voltage should > > change. The assumption is that drivers like CPUfreq or devfreq > > will register for the OPP notifiers and adjust the voltage > > according to suggestions that AVS makes. > > > > This patch is devired from [1] submitted by Stephen. > > [1] https://lore.kernel.org/patchwork/patch/599279/ > > > > Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> > > Signed-off-by: Roger Lu <roger.lu@mediatek.com> > > --- > > drivers/opp/core.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ > > include/linux/pm_opp.h | 11 +++++++ > > 2 files changed, 89 insertions(+) > > This is an rcu implementation which got removed long back from OPP core. Please > align this with the latest changes. > /** * dev_pm_opp_adjust_voltage() - helper to change the voltage of an OPP * @dev: device for which we do this operation * @freq: OPP frequency to adjust voltage of * @u_volt: new OPP voltage * * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the * copy operation, returns 0 if no modifcation was done OR modification was * successful. */ int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, unsigned long u_volt) { struct opp_table *opp_table; struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV); int r = 0; /* Find the opp_table */ opp_table = _find_opp_table(dev); if (IS_ERR(opp_table)) { r = PTR_ERR(opp_table); dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r); return r; } mutex_lock(&opp_table->lock); /* Do we have the frequency? */ list_for_each_entry(tmp_opp, &opp_table->opp_list, node) { if (tmp_opp->rate == freq) { opp = tmp_opp; break; } } if (IS_ERR(opp)) { r = PTR_ERR(opp); goto adjust_unlock; } /* Is update really needed? */ if (opp->supplies->u_volt == u_volt) goto adjust_unlock; opp->supplies->u_volt = u_volt; dev_pm_opp_get(opp); mutex_unlock(&opp_table->lock); /* Notify the voltage change of the OPP */ blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADJUST_VOLTAGE, opp); dev_pm_opp_put(opp); goto adjust_put_table; adjust_unlock: mutex_unlock(&opp_table->lock); adjust_put_table: dev_pm_opp_put_opp_table(opp_table); return r; } Sincerely, Roger Lu.
On 29-07-19, 11:39, Roger Lu wrote: > Dear Stephen Boyd, > > This patch is derived from [1]. Please kindly shares the suggestion to > us. Thanks very much. > > [1]: https://lore.kernel.org/patchwork/patch/599279/ > > Dear Viresh, > > I followed _opp_set_availability() coding style to refine > dev_pm_opp_adjust_voltage() from this patch. Is this refinement suitable > for OPP core? Thanks a lot. Looks okay from a quick look.
diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 0420f7e8ad5b..879ca5f50d1a 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -1946,6 +1946,84 @@ static int _opp_set_availability(struct device *dev, unsigned long freq, return r; } +/* + * dev_pm_opp_adjust_voltage() - helper to change the voltage of an OPP + * @dev: device for which we do this operation + * @freq: OPP frequency to adjust voltage of + * @u_volt: new OPP voltage + * + * Change the voltage of an OPP with an RCU operation. + * + * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the + * copy operation, returns 0 if no modifcation was done OR modification was + * successful. + * + * Locking: The internal device_opp and opp structures are RCU protected. + * Hence this function internally uses RCU updater strategy with mutex locks to + * keep the integrity of the internal data structures. Callers should ensure + * that this function is *NOT* called under RCU protection or in contexts where + * mutex locking or synchronize_rcu() blocking calls cannot be used. + */ +int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, + unsigned long u_volt) +{ + struct opp_table *opp_table; + struct dev_pm_opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV); + int r = 0; + + /* Find the opp_table */ + opp_table = _find_opp_table(dev); + if (IS_ERR(opp_table)) { + r = PTR_ERR(opp_table); + dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r); + return r; + } + + /* keep the node allocated */ + new_opp = kmalloc(sizeof(*new_opp), GFP_KERNEL); + if (!new_opp) + return -ENOMEM; + + mutex_lock(&opp_table->lock); + + /* Do we have the frequency? */ + list_for_each_entry(tmp_opp, &opp_table->opp_list, node) { + if (tmp_opp->rate == freq) { + opp = tmp_opp; + break; + } + } + + if (IS_ERR(opp)) { + r = PTR_ERR(opp); + goto unlock; + } + + /* Is update really needed? */ + if (opp->supplies->u_volt == u_volt) + goto unlock; + + /* copy the old data over */ + *new_opp = *opp; + + /* plug in new node */ + new_opp->supplies->u_volt = u_volt; + + list_replace_rcu(&opp->node, &new_opp->node); + mutex_unlock(&opp_table->lock); + + /* Notify the change of the OPP */ + blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADJUST_VOLTAGE, + opp); + + return 0; + +unlock: + mutex_unlock(&opp_table->lock); + kfree(new_opp); + return r; +} + /** * dev_pm_opp_enable() - Enable a specific OPP * @dev: device for which we do this operation diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 24c757a32a7b..70219fe3ca20 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -25,6 +25,7 @@ struct opp_table; enum dev_pm_opp_event { OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE, + OPP_EVENT_ADJUST_VOLTAGE, }; /** @@ -112,6 +113,9 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, void dev_pm_opp_remove(struct device *dev, unsigned long freq); void dev_pm_opp_remove_all_dynamic(struct device *dev); +int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, + unsigned long u_volt); + int dev_pm_opp_enable(struct device *dev, unsigned long freq); int dev_pm_opp_disable(struct device *dev, unsigned long freq); @@ -229,6 +233,13 @@ static inline void dev_pm_opp_remove_all_dynamic(struct device *dev) { } +static inline int +dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq, + unsigned long u_volt) +{ + return 0; +} + static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq) { return 0;