OPP: Support multiple power-domains per device
Subsystems (6)
v3 cover OPP: Support multiple power-domains per device
Hello,
This series improves the OPP core (and a bit of genpd core as well) to support multiple phandles in the "required-opps" property, which are only used for multiple power-domains per device for now.
We still don't propagate the changes to master domains for the sub-domains, but this patchset is an important stepping stone for that to happen.
Tested on Hikey960 after faking some power domains for CPUs.
V2->V3:
- Gained an additional patch to properly name the virtual device (1/10)
- Renamed the virtual device as virt_dev instead of genpd_dev.
- Few helpers renamed as well accordingly.
- Use container_of() instead of traversing list of genpd.
- Included tags received from Ulf.
V1->V2:
- Had a discussion at Linaro connect with Ulf regarding the changes V1 did in the genpd core and what his objections are to them. Based on his suggestions many changes are made.
- The OPP core still needs the virtual device pointers to set the performance state for multiple domains, but the genpd core doesn't provide them automatically to the OPP core. One of the reasons behind this is to give more power to the consumer drivers which may not want to enable all the genpds at once.
- The consumer drivers would now need to call the APIs dev_pm_opp_{set|put}_genpd_device() in order to set/reset these virtual device pointers.
- More locking is put in place to protect the genpd device pointers in OPP core.
- Reorg of the code at many places to make code less redundant.
--
viresh
Viresh Kumar (10):
PM / Domains: Rename genpd virtual devices as virt_dev
OPP: Identify and mark genpd OPP tables
OPP: Separate out custom OPP handler specific code
OPP: Populate required opp tables from "required-opps" property
OPP: Populate OPPs from "required-opps" property
PM / Domains: Add genpd_opp_to_performance_state()
OPP: Add dev_pm_opp_{set|put}_genpd_virt_dev() helper
OPP: Configure all required OPPs
OPP: Rename and relocate of_genpd_opp_to_performance_state()
OPP: Remove of_dev_pm_opp_find_required_opp()
drivers/base/power/domain.c | 70 ++++---- drivers/opp/core.c | 261 ++++++++++++++++++++++-------- drivers/opp/of.c | 313 +++++++++++++++++++++++++++++++----- drivers/opp/opp.h | 20 +++ include/linux/pm_domain.h | 8 +- include/linux/pm_opp.h | 16 +- 6 files changed, 526 insertions(+), 162 deletions(-)
Signature · 1 line
2.19.1.568.g152ad8e3369a
PATCH v3 1/10 PM / Domains: Rename genpd virtual devices as virt_dev
There are several struct device instances that genpd core handles. The most common one is the consumer device structure, which is named (correctly) as "dev" within genpd core. The second one is the genpd's device structure, referenced as genpd->dev. The third one is the virtual device structures created by the genpd core to represent the consumer device for multiple power domain case, currently named as genpd_dev. The naming of these virtual devices isn't very clear or readable and it looks more like the genpd->dev.
Rename the virtual device instances within the genpd core as "virt_dev".
--- drivers/base/power/domain.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
drivers/base/power/domain.c +13 -13
@@ -2338,7 +2338,7 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);struct device *genpd_dev_pm_attach_by_id (struct device *dev,unsigned int index) { -struct device *genpd_dev; +struct device *virt_dev;int num_domains;int ret;
@@ -2352,31 +2352,31 @@ struct device *genpd_dev_pm_attach_by_id(struct device *dev,return NULL ;/* Allocate and register device on the genpd bus. */ - genpd_dev =kzalloc (sizeof (*genpd_dev),GFP_KERNEL ); -if (!genpd_dev) + virt_dev =kzalloc (sizeof (*virt_dev),GFP_KERNEL ); +if (!virt_dev)return ERR_PTR (-ENOMEM ); -dev_set_name (genpd_dev,"genpd:%u:%s" , index,dev_name (dev)); - genpd_dev->bus = &genpd_bus_type; - genpd_dev->release = genpd_release_dev; +dev_set_name (virt_dev,"genpd:%u:%s" , index,dev_name (dev)); + virt_dev->bus = &genpd_bus_type; + virt_dev->release = genpd_release_dev; - ret =device_register (genpd_dev); + ret =device_register (virt_dev);if (ret) { -kfree (genpd_dev); +kfree (virt_dev);return ERR_PTR (ret); }/* Try to attach the device to the PM domain at the specified index. */ - ret =__genpd_dev_pm_attach (genpd_dev, dev->of_node, index, false); + ret =__genpd_dev_pm_attach (virt_dev, dev->of_node, index, false);if (ret <1 ) { -device_unregister (genpd_dev); +device_unregister (virt_dev);return ret ?ERR_PTR (ret) :NULL ; } -pm_runtime_enable (genpd_dev); -genpd_queue_power_off_work (dev_to_genpd (genpd_dev)); +pm_runtime_enable (virt_dev); +genpd_queue_power_off_work (dev_to_genpd (virt_dev)); -return genpd_dev; +return virt_dev; }EXPORT_SYMBOL_GPL (genpd_dev_pm_attach_by_id);
Signature · 1 line
2.19.1.568.g152ad8e3369a
Re: [PATCH V3 01/10] PM / Domains: Rename genpd virtual devices as virt_dev
Quoted 9 lines · Viresh Kumar
There are several struct device instances that genpd core handles. The most common one is the consumer device structure, which is named (correctly) as "dev" within genpd core. The second one is the genpd's device structure, referenced as
genpd->dev. The third one is the virtual device structures created by the genpd core to represent the consumer device for multiple power domain case, currently named asgenpd_dev. The naming of these virtual devices isn't very clear or readable and it looks more like thegenpd->dev.
Quoted 3 lines
Rename the virtual device instances within the genpd core as "
virt_dev".Signed-off-by Viresh Kumar <[email protected]>
Thanks, this make the code more clear!
Kind regards
Uffe
Quoted 64 lines
--- drivers/base/power/domain.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)drivers/base/power/domain.c +13
-14@@ -2338,7 +2338,7 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);struct device *genpd_dev_pm_attach_by_id (struct device *dev,unsigned int index) { -struct device *genpd_dev; +struct device *virt_dev;int num_domains;int ret;@@ -2352,31 +2352,31 @@ struct device *genpd_dev_pm_attach_by_id(struct device *dev,return NULL ;/* Allocate and register device on the genpd bus. */ - genpd_dev =kzalloc (sizeof (*genpd_dev),GFP_KERNEL ); -if (!genpd_dev) + virt_dev =kzalloc (sizeof (*virt_dev),GFP_KERNEL ); +if (!virt_dev)return ERR_PTR (-ENOMEM ); -dev_set_name (genpd_dev,"genpd:%u:%s" , index,dev_name (dev)); - genpd_dev->bus = &genpd_bus_type; - genpd_dev->release = genpd_release_dev; +dev_set_name (virt_dev,"genpd:%u:%s" , index,dev_name (dev)); + virt_dev->bus = &genpd_bus_type; + virt_dev->release = genpd_release_dev; - ret =device_register (genpd_dev); + ret =device_register (virt_dev);if (ret) { -kfree (genpd_dev); +kfree (virt_dev);return ERR_PTR (ret); }/* Try to attach the device to the PM domain at the specified index. */ - ret =__genpd_dev_pm_attach (genpd_dev, dev->of_node, index, false); + ret =__genpd_dev_pm_attach (virt_dev, dev->of_node, index, false);if (ret <1 ) { -device_unregister (genpd_dev); +device_unregister (virt_dev);return ret ?ERR_PTR (ret) :NULL ; } -pm_runtime_enable (genpd_dev); -genpd_queue_power_off_work (dev_to_genpd (genpd_dev)); +pm_runtime_enable (virt_dev); +genpd_queue_power_off_work (dev_to_genpd (virt_dev)); -return genpd_dev; +return virt_dev; }EXPORT_SYMBOL_GPL (genpd_dev_pm_attach_by_id); --2.19.1.568.g152ad8e3369a
PATCH v3 2/10 OPP: Identify and mark genpd OPP tables
In reply to Viresh KumarWe need to handle genpd OPP tables differently, this is already the case at one location and will be extended going forward. Add another field to the OPP table to check if the table belongs to a genpd or not.
--- drivers/opp/of.c | 6 ++++-- drivers/opp/opp.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-)
drivers/opp/of.c +4 -2
@@ -92,6 +92,9 @@ void _of_init_opp_table(struct opp_table *opp_table, struct device *dev,of_property_read_u32 (np,"voltage-tolerance" , &opp_table->voltage_tolerance_v1); +if (of_find_property (np,"#power-domain-cells" ,NULL )) + opp_table->is_genpd = true; +/* Get OPP table node */ opp_np =_opp_of_get_opp_desc_node (np, index);of_node_put (np);
@@ -326,8 +329,7 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table, ret =of_property_read_u64 (np,"opp-hz" , &rate);if (ret <0 ) {/* "opp-hz" is optional for devices like power domains. */ -if (!of_find_property (dev->of_node,"#power-domain-cells" , -NULL )) { +if (!opp_table->is_genpd) {dev_err (dev,"%s: opp-hz not found\n" , __func__); goto free_opp; }
drivers/opp/opp.h +2 -0
@@ -140,6 +140,7 @@ enum opp_table_access {* @regulators: Supply regulators * @regulator_count: Number of power supply regulators * @genpd_performance_state: Device's power domain support performance state. +* @is_genpd: Marks if the OPP table belongs to a genpd. * @set_opp: Platform specific 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).
@@ -178,6 +179,7 @@ struct opp_table {struct regulator **regulators;unsigned int regulator_count;bool genpd_performance_state; +bool is_genpd;int (*set_opp)(struct dev_pm_set_opp_data *data);struct dev_pm_set_opp_data *set_opp_data;
Signature · 1 line
2.19.1.568.g152ad8e3369a
PATCH v3 3/10 OPP: Separate out custom OPP handler specific code
In reply to Viresh KumarCreate a separate routine to take care of custom set_opp() handler specific stuff.
--- drivers/opp/core.c | 67 +++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 27 deletions(-)
drivers/opp/core.c +40 -27
@@ -635,6 +635,34 @@ static int _generic_set_opp_regulator(const struct opp_table *opp_table,return ret; } +static int _set_opp_custom (const struct opp_table *opp_table, +struct device *dev,unsigned long old_freq, +unsigned long freq, +struct dev_pm_opp_supply *old_supply, +struct dev_pm_opp_supply *new_supply) +{ +struct dev_pm_set_opp_data *data; +int size; + + data = opp_table->set_opp_data; + data->regulators = opp_table->regulators; + data->regulator_count = opp_table->regulator_count; + data->clk = opp_table->clk; + data->dev = dev; + + data->old_opp.rate = old_freq; + size =sizeof (*old_supply) * opp_table->regulator_count; +if (IS_ERR (old_supply)) +memset (data->old_opp.supplies,0 , size); +else +memcpy (data->old_opp.supplies, old_supply, size); + + data->new_opp.rate = freq; +memcpy (data->new_opp.supplies, new_supply, size); + +return opp_table->set_opp (data); +} +/** * dev_pm_opp_set_rate() - Configure new OPP based on frequency * @dev: device for which we do this operation
@@ -649,7 +677,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)unsigned long freq, old_freq;struct dev_pm_opp *old_opp, *opp;struct clk *clk; -int ret, size; +int ret;if (unlikely (!target_freq)) { dev_err(dev, "%s: Invalid target frequency %lu\n", __func__,
@@ -702,8 +730,17 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)dev_dbg (dev,"%s: switching OPP: %lu Hz --> %lu Hz\n" , __func__, old_freq, freq); -/* Only frequency scaling */ -if (!opp_table->regulators) { +if (opp_table->set_opp) { + ret =_set_opp_custom (opp_table, dev, old_freq, freq, +IS_ERR (old_opp) ?NULL : old_opp->supplies, + opp->supplies); + }else if (opp_table->regulators) { + ret =_generic_set_opp_regulator (opp_table, dev, old_freq, freq, +IS_ERR (old_opp) ?NULL : old_opp->supplies, + opp->supplies); + }else { +/* Only frequency scaling */ +/* * We don't support devices with both regulator and * domain performance-state for now.
@@ -714,30 +751,6 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) opp->pstate); else ret =_generic_set_opp_clk_only (dev, clk, old_freq, freq); - }else if (!opp_table->set_opp) { - ret =_generic_set_opp_regulator (opp_table, dev, old_freq, freq, -IS_ERR (old_opp) ?NULL : old_opp->supplies, - opp->supplies); - }else { -struct dev_pm_set_opp_data *data; - - data = opp_table->set_opp_data; - data->regulators = opp_table->regulators; - data->regulator_count = opp_table->regulator_count; - data->clk = clk; - data->dev = dev; - - data->old_opp.rate = old_freq; - size =sizeof (*opp->supplies) * opp_table->regulator_count; -if (IS_ERR (old_opp)) -memset (data->old_opp.supplies,0 , size); -else -memcpy (data->old_opp.supplies, old_opp->supplies, size); - - data->new_opp.rate = freq; -memcpy (data->new_opp.supplies, opp->supplies, size); - - ret = opp_table->set_opp (data); }dev_pm_opp_put (opp);
Signature · 1 line
2.19.1.568.g152ad8e3369a
PATCH v3 4/10 OPP: Populate required opp tables from "required-opps" property
In reply to Viresh KumarThe current implementation works only for the case where a single phandle is present in the "required-opps" property, while DT allows multiple phandles to be present there.
This patch adds new infrastructure to parse all the phandles present in "required-opps" property and save pointers of the required OPP's OPP tables. These will be used by later commits.
--- drivers/opp/core.c | 2 + drivers/opp/of.c | 147 +++++++++++++++++++++++++++++++++++++++++++++ drivers/opp/opp.h | 8 +++ 3 files changed, 157 insertions(+)
drivers/opp/core.c +2 -0
@@ -901,6 +901,8 @@ static void _opp_table_kref_release(struct kref *kref) struct opp_table *opp_table = container_of(kref, struct opp_table, kref);struct opp_device *opp_dev, *temp; +_of_clear_opp_table (opp_table); +/* Release clk */ if (!IS_ERR (opp_table->clk))clk_put (opp_table->clk);
drivers/opp/of.c +147 -0
162 lines not on this page · raw message
drivers/opp/opp.h +8 -0
@@ -133,6 +133,9 @@ enum opp_table_access {* @parsed_static_opps: True if OPPs are initialized from DT. * @shared_opp: OPP is shared between multiple devices. * @suspend_opp: Pointer to OPP to be used during device suspend. +* @required_opp_tables: List of device OPP tables that are required by OPPs in +* this table. +* @required_opp_count: Number of required devices. * @supported_hw: Array of version number to support. * @supported_hw_count: Number of elements in supported_hw array. * @prop_name: A name to postfix to many DT properties, while parsing them.
@@ -172,6 +175,9 @@ struct opp_table {enum opp_table_access shared_opp;struct dev_pm_opp *suspend_opp; +struct opp_table **required_opp_tables; +unsigned int required_opp_count; +unsigned int *supported_hw;unsigned int supported_hw_count;const char *prop_name;
@@ -208,9 +214,11 @@ void _put_opp_list_kref(struct opp_table *opp_table);#ifdef CONFIG_OF void _of_init_opp_table (struct opp_table *opp_table,struct device *dev,int index); +void _of_clear_opp_table (struct opp_table *opp_table);struct opp_table *_managed_opp (struct device *dev,int index);#else static inline void _of_init_opp_table (struct opp_table *opp_table,struct device *dev,int index) {} +static inline void _of_clear_opp_table (struct opp_table *opp_table) {}static inline struct opp_table *_managed_opp (struct device *dev,int index) {return NULL ; }#endif
Signature · 1 line
2.19.1.568.g152ad8e3369a
PATCH v3 5/10 OPP: Populate OPPs from "required-opps" property
In reply to Viresh KumarAn earlier commit populated the OPP tables from the "required-opps" property, this commit populates the individual OPPs. This is repeated for each OPP in the OPP table and these populated OPPs will be used by later commits.
--- drivers/opp/core.c | 1 + drivers/opp/of.c | 81 ++++++++++++++++++++++++++++++++++++++++++++-- drivers/opp/opp.h | 6 ++++ 3 files changed, 86 insertions(+), 2 deletions(-)
drivers/opp/core.c +1 -0
@@ -976,6 +976,7 @@ static void _opp_kref_release(struct kref *kref)* frequency/voltage list. */ blocking_notifier_call_chain (&opp_table->head,OPP_EVENT_REMOVE , opp); +_of_opp_free_required_opps (opp_table, opp);opp_debug_remove_one (opp);list_del (&opp->node);kfree (opp);
drivers/opp/of.c +79 -2
111 lines not on this page · raw message
drivers/opp/opp.h +6 -0
@@ -63,6 +63,7 @@ extern struct list_head opp_tables;* @supplies: Power supplies voltage/current values * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's * frequency from any other OPP's frequency. +* @required_opps: List of OPPs that are required by this OPP. * @opp_table: points back to the opp_table struct this opp belongs to * @np: OPP's device node. * @dentry: debugfs dentry pointer (per opp)
@@ -84,6 +85,7 @@ struct dev_pm_opp {unsigned long clock_latency_ns; +struct dev_pm_opp **required_opps;struct opp_table *opp_table;struct device_node *np;
@@ -216,10 +218,14 @@ void _put_opp_list_kref(struct opp_table *opp_table);void _of_init_opp_table (struct opp_table *opp_table,struct device *dev,int index);void _of_clear_opp_table (struct opp_table *opp_table);struct opp_table *_managed_opp (struct device *dev,int index); +void _of_opp_free_required_opps (struct opp_table *opp_table, +struct dev_pm_opp *opp);#else static inline void _of_init_opp_table (struct opp_table *opp_table,struct device *dev,int index) {}static inline void _of_clear_opp_table (struct opp_table *opp_table) {}static inline struct opp_table *_managed_opp (struct device *dev,int index) {return NULL ; } +static inline void _of_opp_free_required_opps (struct opp_table *opp_table, +struct dev_pm_opp *opp) {}#endif #ifdef CONFIG_DEBUG_FS
Signature · 1 line
2.19.1.568.g152ad8e3369a
PATCH v3 6/10 PM / Domains: Add genpd_opp_to_performance_state()
In reply to Viresh KumarThe OPP core currently stores the performance state in the consumer device's OPP table, but that is going to change going forward and performance state will rather be set directly in the genpd's OPP table.
For that we need to get the performance state for genpd's device structure (genpd->dev) instead of the consumer device's structure. Add a new helper to do that.
--- drivers/base/power/domain.c | 32 ++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 9 +++++++++ 2 files changed, 41 insertions(+)
drivers/base/power/domain.c +32 -0
@@ -2520,6 +2520,38 @@ int of_genpd_parse_idle_states(struct device_node *dn, }EXPORT_SYMBOL_GPL (of_genpd_parse_idle_states); +/** +* pm_genpd_opp_to_performance_state - Gets performance state of the genpd from its OPP node. +* +* @genpd_dev: Genpd's device for which the performance-state needs to be found. +* @opp: struct dev_pm_opp of the OPP for which we need to find performance +* state. +* +* Returns performance state encoded in the OPP of the genpd. This calls +* platform specific genpd->opp_to_performance_state() callback to translate +* power domain OPP to performance state. +* +* Returns performance state on success and 0 on failure. +*/ +unsigned int pm_genpd_opp_to_performance_state (struct device *genpd_dev, +struct dev_pm_opp *opp) +{ +struct generic_pm_domain *genpd =NULL ; +int state; + + genpd = container_of(genpd_dev, struct generic_pm_domain, dev); + +if (unlikely (!genpd->opp_to_performance_state)) +return 0 ; + +genpd_lock (genpd); + state = genpd->opp_to_performance_state (genpd, opp); +genpd_unlock (genpd); + +return state; +} +EXPORT_SYMBOL_GPL (pm_genpd_opp_to_performance_state); +/** * of_genpd_opp_to_performance_state- Gets performance state of device's * power domain corresponding to a DT node's "required-opps" property.
include/linux/pm_domain.h +9 -0
@@ -258,6 +258,8 @@ int of_genpd_add_subdomain(struct of_phandle_args *parent,struct generic_pm_domain *of_genpd_remove_last (struct device_node *np);int of_genpd_parse_idle_states (struct device_node *dn,struct genpd_power_state **states,int *n); +unsigned int pm_genpd_opp_to_performance_state (struct device *genpd_dev, +struct dev_pm_opp *opp);unsigned int of_genpd_opp_to_performance_state (struct device *dev,struct device_node *np);
@@ -299,6 +301,13 @@ static inline int of_genpd_parse_idle_states(struct device_node *dn,return -ENODEV ; } +static inline unsigned int +pm_genpd_opp_to_performance_state (struct device *genpd_dev, +struct dev_pm_opp *opp) +{ +return 0 ; +} +static inline unsigned int of_genpd_opp_to_performance_state (struct device *dev,struct device_node *np)
Signature · 1 line
2.19.1.568.g152ad8e3369a
Re: [PATCH V3 06/10] PM / Domains: Add genpd_opp_to_performance_state()
Quoted 9 lines · Viresh Kumar
The OPP core currently stores the performance state in the consumer device's OPP table, but that is going to change going forward and performance state will rather be set directly in the genpd's OPP table.
For that we need to get the performance state for genpd's device structure (
genpd->dev) instead of the consumer device's structure. Add a new helper to do that.Signed-off-by Viresh Kumar <[email protected]>
Kind regards
Uffe
Quoted 78 lines
--- drivers/base/power/domain.c | 32 ++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 9 +++++++++ 2 files changed, 41 insertions(+)drivers/base/power/domain.c +32
-0@@ -2520,6 +2520,38 @@ int of_genpd_parse_idle_states(struct device_node *dn, }EXPORT_SYMBOL_GPL (of_genpd_parse_idle_states); +/** +* pm_genpd_opp_to_performance_state - Gets performance state of the genpd from its OPP node. +* +* @genpd_dev: Genpd's device for which the performance-state needs to be found. +* @opp: struct dev_pm_opp of the OPP for which we need to find performance +* state. +* +* Returns performance state encoded in the OPP of the genpd. This calls +* platform specific genpd->opp_to_performance_state() callback to translate +* power domain OPP to performance state. +* +* Returns performance state on success and 0 on failure. +*/ +unsigned int pm_genpd_opp_to_performance_state (struct device *genpd_dev, +struct dev_pm_opp *opp) +{ +struct generic_pm_domain *genpd =NULL ; +int state; + + genpd = container_of(genpd_dev, struct generic_pm_domain, dev); + +if (unlikely (!genpd->opp_to_performance_state)) +return 0 ; + +genpd_lock (genpd); + state = genpd->opp_to_performance_state (genpd, opp); +genpd_unlock (genpd); + +return state; +} +EXPORT_SYMBOL_GPL (pm_genpd_opp_to_performance_state); +/** * of_genpd_opp_to_performance_state- Gets performance state of device's * power domain corresponding to a DT node's "required-opps" property. include/linux/pm_domain.h +9
-1@@ -258,6 +258,8 @@ int of_genpd_add_subdomain(struct of_phandle_args *parent,struct generic_pm_domain *of_genpd_remove_last (struct device_node *np);int of_genpd_parse_idle_states (struct device_node *dn,struct genpd_power_state **states,int *n); +unsigned int pm_genpd_opp_to_performance_state (struct device *genpd_dev, +struct dev_pm_opp *opp);unsigned int of_genpd_opp_to_performance_state (struct device *dev,struct device_node *np);@@ -299,6 +301,13 @@ static inline int of_genpd_parse_idle_states(struct device_node *dn,return -ENODEV ; } +static inline unsigned int +pm_genpd_opp_to_performance_state (struct device *genpd_dev, +struct dev_pm_opp *opp) +{ +return 0 ; +} +static inline unsigned int of_genpd_opp_to_performance_state (struct device *dev,struct device_node *np) --2.19.1.568.g152ad8e3369a
PATCH v3 7/10 OPP: Add dev_pm_opp_{set|put}_genpd_virt_dev() helper
In reply to Viresh KumarMultiple generic power domains for a consumer device are supported with the help of virtual devices, which are created for each consumer device
- genpd pair. These are the device structures which are attached to the power domain and are required by the OPP core to set the performance state of the genpd.
The helpers added by this commit are required to be called once for each of these virtual devices. These are required only if multiple domains are available for a device, otherwise the actual device structure will be used instead by the OPP core.
The new helpers also support the complex cases where the consumer device wouldn't always require all the domains. For example, a camera may require only one power domain during normal operations but two during high resolution operations. The consumer driver can call dev_pm_opp_put_genpd_virt_dev(high_resolution_genpd_virt_dev) if it is currently operating in the normal mode and doesn't have any performance requirements from the genpd which manages high resolution power requirements. The consumer driver can later call dev_pm_opp_set_genpd_virt_dev(high_resolution_genpd_virt_dev) once it switches back to the high resolution mode.
The new helpers differ from other OPP set/put helpers as the new ones can be called with OPPs initialized for the table as we may need to call them on the fly because of the complex case explained above. For this reason it is possible that the genpd virt_dev structure may be used in parallel while the new helpers are running and a new mutex is added to protect against that. We didn't use the existing opp_table->lock mutex as that is widely used in the OPP core and we will need this lock in the dev_pm_opp_set_rate() helper while changing OPP and we need to make sure there is not much contention while doing that as that's the hotpath.
--- drivers/opp/core.c | 88 ++++++++++++++++++++++++++++++++++++++++++ drivers/opp/of.c | 16 +++++++- drivers/opp/opp.h | 4 ++ include/linux/pm_opp.h | 8 ++++ 4 files changed, 115 insertions(+), 1 deletion(-)
drivers/opp/core.c +88 -0
@@ -823,6 +823,7 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)return NULL ;mutex_init (&opp_table->lock); +mutex_init (&opp_table->genpd_virt_dev_lock);INIT_LIST_HEAD (&opp_table->dev_list); opp_dev =_add_opp_dev (dev, opp_table);
@@ -920,6 +921,7 @@ static void _opp_table_kref_release(struct kref *kref)_remove_opp_dev (opp_dev, opp_table); } +mutex_destroy (&opp_table->genpd_virt_dev_lock);mutex_destroy (&opp_table->lock);list_del (&opp_table->node);kfree (opp_table);
@@ -1602,6 +1604,92 @@ void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) }EXPORT_SYMBOL_GPL (dev_pm_opp_unregister_set_opp_helper); +/** +* dev_pm_opp_set_genpd_virt_dev - Set virtual genpd device for an index +* @dev: Consumer device for which the genpd device is getting set. +* @virt_dev: virtual genpd device. +* @index: index. +* +* Multiple generic power domains for a device are supported with the help of +* virtual genpd devices, which are created for each consumer device - genpd +* pair. These are the device structures which are attached to the power domain +* and are required by the OPP core to set the performance state of the genpd. +* +* This helper will normally be called by the consumer driver of the device +* "dev", as only that has details of the genpd devices. +* +* This helper needs to be called once for each of those virtual devices, but +* only if multiple domains are available for a device. Otherwise the original +* device structure will be used instead by the OPP core. +*/ +struct opp_table *dev_pm_opp_set_genpd_virt_dev (struct device *dev, +struct device *virt_dev, +int index) +{ +struct opp_table *opp_table; + + opp_table =dev_pm_opp_get_opp_table (dev); +if (!opp_table) +return ERR_PTR (-ENOMEM ); + +mutex_lock (&opp_table->genpd_virt_dev_lock); + +if (unlikely (!opp_table->genpd_virt_devs || + index >= opp_table->required_opp_count || + opp_table->genpd_virt_devs[index])) { + +dev_err (dev,"Invalid request to set required device\n" ); +dev_pm_opp_put_opp_table (opp_table); +mutex_unlock (&opp_table->genpd_virt_dev_lock); + +return ERR_PTR (-EINVAL ); + } + + opp_table->genpd_virt_devs[index] = virt_dev; +mutex_unlock (&opp_table->genpd_virt_dev_lock); + +return opp_table; +} + +/** +* dev_pm_opp_put_genpd_virt_dev() - Releases resources blocked for genpd device. +* @opp_table: OPP table returned by dev_pm_opp_set_genpd_virt_dev(). +* @virt_dev: virtual genpd device. +* +* This releases the resource previously acquired with a call to +* dev_pm_opp_set_genpd_virt_dev(). The consumer driver shall call this helper +* if it doesn't want OPP core to update performance state of a power domain +* anymore. +*/ +void dev_pm_opp_put_genpd_virt_dev (struct opp_table *opp_table, +struct device *virt_dev) +{ +int i; + +/* +* Acquire genpd_virt_dev_lock to make sure virt_dev isn't getting +* used in parallel. +*/ +mutex_lock (&opp_table->genpd_virt_dev_lock); + +for (i =0 ; i < opp_table->required_opp_count; i++) { +if (opp_table->genpd_virt_devs[i] != virt_dev) +continue ; + + opp_table->genpd_virt_devs[i] =NULL ; +dev_pm_opp_put_opp_table (opp_table); + +/* Drop the vote */ +dev_pm_genpd_set_performance_state (virt_dev,0 ); +break ; + } + +mutex_unlock (&opp_table->genpd_virt_dev_lock); + +if (unlikely (i == opp_table->required_opp_count)) +dev_err (virt_dev,"Failed to find required device entry\n" ); +} +/** * dev_pm_opp_add() - Add an OPP table from a table definitions * @dev: device for which we do this operation
drivers/opp/of.c +15 -1
@@ -134,6 +134,7 @@ static struct opp_table *_find_table_of_opp_np(struct device_node *opp_np)static void _opp_table_free_required_tables (struct opp_table *opp_table) {struct opp_table **required_opp_tables = opp_table->required_opp_tables; +struct device **genpd_virt_devs = opp_table->genpd_virt_devs;int i;if (!required_opp_tables)
@@ -147,8 +148,10 @@ static void _opp_table_free_required_tables(struct opp_table *opp_table) }kfree (required_opp_tables); +kfree (genpd_virt_devs); opp_table->required_opp_count =0 ; + opp_table->genpd_virt_devs =NULL ; opp_table->required_opp_tables =NULL ; }
@@ -161,6 +164,7 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table, struct device_node *opp_np) {struct opp_table **required_opp_tables; +struct device **genpd_virt_devs =NULL ;struct device_node *required_np, *np;int count, i;
@@ -175,11 +179,21 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,if (!count) goto put_np; +if (count >1 ) { + genpd_virt_devs =kcalloc (count,sizeof (*genpd_virt_devs), +GFP_KERNEL ); +if (!genpd_virt_devs) + goto put_np; + } + required_opp_tables =kcalloc (count,sizeof (*required_opp_tables),GFP_KERNEL ); -if (!required_opp_tables) +if (!required_opp_tables) { +kfree (genpd_virt_devs); goto put_np; + } + opp_table->genpd_virt_devs = genpd_virt_devs; opp_table->required_opp_tables = required_opp_tables; opp_table->required_opp_count = count;
drivers/opp/opp.h +4 -0
@@ -135,6 +135,8 @@ enum opp_table_access {* @parsed_static_opps: True if OPPs are initialized from DT. * @shared_opp: OPP is shared between multiple devices. * @suspend_opp: Pointer to OPP to be used during device suspend. +* @genpd_virt_dev_lock: Mutex protecting the genpd virtual device pointers. +* @genpd_virt_devs: List of virtual devices for multiple genpd support. * @required_opp_tables: List of device OPP tables that are required by OPPs in * this table. * @required_opp_count: Number of required devices.
@@ -177,6 +179,8 @@ struct opp_table {enum opp_table_access shared_opp;struct dev_pm_opp *suspend_opp; +struct mutex genpd_virt_dev_lock; +struct device **genpd_virt_devs;struct opp_table **required_opp_tables;unsigned int required_opp_count;
include/linux/pm_opp.h +8 -0
@@ -126,6 +126,8 @@ struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char * name);void dev_pm_opp_put_clkname (struct opp_table *opp_table);struct opp_table *dev_pm_opp_register_set_opp_helper (struct device *dev,int (*set_opp)(struct dev_pm_set_opp_data *data));void dev_pm_opp_unregister_set_opp_helper (struct opp_table *opp_table); +struct opp_table *dev_pm_opp_set_genpd_virt_dev (struct device *dev,struct device *virt_dev,int index); +void dev_pm_opp_put_genpd_virt_dev (struct opp_table *opp_table,struct device *virt_dev);int dev_pm_opp_set_rate (struct device *dev,unsigned long target_freq);int dev_pm_opp_set_sharing_cpus (struct device *cpu_dev,const struct cpumask *cpumask);int dev_pm_opp_get_sharing_cpus (struct device *cpu_dev,struct cpumask *cpumask);
@@ -272,6 +274,12 @@ static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, conststatic inline void dev_pm_opp_put_clkname (struct opp_table *opp_table) {} +static inline struct opp_table *dev_pm_opp_set_genpd_virt_dev (struct device *dev,struct device *virt_dev,int index) +{ +return ERR_PTR (-ENOTSUPP ); +} + +static inline void dev_pm_opp_put_genpd_virt_dev (struct opp_table *opp_table,struct device *virt_dev) {}static inline int dev_pm_opp_set_rate (struct device *dev,unsigned long target_freq) {return -ENOTSUPP ;
Signature · 1 line
2.19.1.568.g152ad8e3369a
Re: [PATCH V3 07/10] OPP: Add dev_pm_opp_{set|put}_genpd_virt_dev() helper
Quoted 32 lines · Viresh Kumar
Multiple generic power domains for a consumer device are supported with the help of virtual devices, which are created for each consumer device
- genpd pair. These are the device structures which are attached to the power domain and are required by the OPP core to set the performance state of the genpd.The helpers added by this commit are required to be called once for each of these virtual devices. These are required only if multiple domains are available for a device, otherwise the actual device structure will be used instead by the OPP core.
The new helpers also support the complex cases where the consumer device wouldn't always require all the domains. For example, a camera may require only one power domain during normal operations but two during high resolution operations. The consumer driver can call
dev_pm_opp_put_genpd_virt_dev(high_resolution_genpd_virt_dev)if it is currently operating in the normal mode and doesn't have any performance requirements from the genpd which manages high resolution power requirements. The consumer driver can later calldev_pm_opp_set_genpd_virt_dev(high_resolution_genpd_virt_dev)once it switches back to the high resolution mode.The new helpers differ from other OPP set/put helpers as the new ones can be called with OPPs initialized for the table as we may need to call them on the fly because of the complex case explained above. For this reason it is possible that the genpd
virt_devstructure may be used in parallel while the new helpers are running and a new mutex is added to protect against that. We didn't use the existingopp_table->lockmutex as that is widely used in the OPP core and we will need this lock in thedev_pm_opp_set_rate()helper while changing OPP and we need to make sure there is not much contention while doing that as that's the hotpath.
Quoted 1 line
Signed-off-by Viresh Kumar <[email protected]>
Kind regards
Uffe
Quoted 225 lines
--- drivers/opp/core.c | 88 ++++++++++++++++++++++++++++++++++++++++++ drivers/opp/of.c | 16 +++++++- drivers/opp/opp.h | 4 ++ include/linux/pm_opp.h | 8 ++++ 4 files changed, 115 insertions(+), 1 deletion(-)drivers/opp/core.c +88
-0@@ -823,6 +823,7 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)return NULL ;mutex_init (&opp_table->lock); +mutex_init (&opp_table->genpd_virt_dev_lock);INIT_LIST_HEAD (&opp_table->dev_list); opp_dev =_add_opp_dev (dev, opp_table);@@ -920,6 +921,7 @@ static void _opp_table_kref_release(struct kref *kref)_remove_opp_dev (opp_dev, opp_table); } +mutex_destroy (&opp_table->genpd_virt_dev_lock);mutex_destroy (&opp_table->lock);list_del (&opp_table->node);kfree (opp_table);@@ -1602,6 +1604,92 @@ void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) }EXPORT_SYMBOL_GPL (dev_pm_opp_unregister_set_opp_helper); +/** +* dev_pm_opp_set_genpd_virt_dev - Set virtual genpd device for an index +* @dev: Consumer device for which the genpd device is getting set. +* @virt_dev: virtual genpd device. +* @index: index. +* +* Multiple generic power domains for a device are supported with the help of +* virtual genpd devices, which are created for each consumer device - genpd +* pair. These are the device structures which are attached to the power domain +* and are required by the OPP core to set the performance state of the genpd. +* +* This helper will normally be called by the consumer driver of the device +* "dev", as only that has details of the genpd devices. +* +* This helper needs to be called once for each of those virtual devices, but +* only if multiple domains are available for a device. Otherwise the original +* device structure will be used instead by the OPP core. +*/ +struct opp_table *dev_pm_opp_set_genpd_virt_dev (struct device *dev, +struct device *virt_dev, +int index) +{ +struct opp_table *opp_table; + + opp_table =dev_pm_opp_get_opp_table (dev); +if (!opp_table) +return ERR_PTR (-ENOMEM ); + +mutex_lock (&opp_table->genpd_virt_dev_lock); + +if (unlikely (!opp_table->genpd_virt_devs || + index >= opp_table->required_opp_count || + opp_table->genpd_virt_devs[index])) { + +dev_err (dev,"Invalid request to set required device\n" ); +dev_pm_opp_put_opp_table (opp_table); +mutex_unlock (&opp_table->genpd_virt_dev_lock); + +return ERR_PTR (-EINVAL ); + } + + opp_table->genpd_virt_devs[index] = virt_dev; +mutex_unlock (&opp_table->genpd_virt_dev_lock); + +return opp_table; +} + +/** +* dev_pm_opp_put_genpd_virt_dev() - Releases resources blocked for genpd device. +* @opp_table: OPP table returned by dev_pm_opp_set_genpd_virt_dev(). +* @virt_dev: virtual genpd device. +* +* This releases the resource previously acquired with a call to +* dev_pm_opp_set_genpd_virt_dev(). The consumer driver shall call this helper +* if it doesn't want OPP core to update performance state of a power domain +* anymore. +*/ +void dev_pm_opp_put_genpd_virt_dev (struct opp_table *opp_table, +struct device *virt_dev) +{ +int i; + +/* +* Acquire genpd_virt_dev_lock to make sure virt_dev isn't getting +* used in parallel. +*/ +mutex_lock (&opp_table->genpd_virt_dev_lock); + +for (i =0 ; i < opp_table->required_opp_count; i++) { +if (opp_table->genpd_virt_devs[i] != virt_dev) +continue ; + + opp_table->genpd_virt_devs[i] =NULL ; +dev_pm_opp_put_opp_table (opp_table); + +/* Drop the vote */ +dev_pm_genpd_set_performance_state (virt_dev,0 ); +break ; + } + +mutex_unlock (&opp_table->genpd_virt_dev_lock); + +if (unlikely (i == opp_table->required_opp_count)) +dev_err (virt_dev,"Failed to find required device entry\n" ); +} +/** * dev_pm_opp_add() - Add an OPP table from a table definitions * @dev: device for which we do this operation drivers/opp/of.c +15
-1@@ -134,6 +134,7 @@ static struct opp_table *_find_table_of_opp_np(struct device_node *opp_np)static void _opp_table_free_required_tables (struct opp_table *opp_table) {struct opp_table **required_opp_tables = opp_table->required_opp_tables; +struct device **genpd_virt_devs = opp_table->genpd_virt_devs;int i;if (!required_opp_tables)@@ -147,8 +148,10 @@ static void _opp_table_free_required_tables(struct opp_table *opp_table) }kfree (required_opp_tables); +kfree (genpd_virt_devs); opp_table->required_opp_count =0 ; + opp_table->genpd_virt_devs =NULL ; opp_table->required_opp_tables =NULL ; }@@ -161,6 +164,7 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table, struct device_node *opp_np) {struct opp_table **required_opp_tables; +struct device **genpd_virt_devs =NULL ;struct device_node *required_np, *np;int count, i;@@ -175,11 +179,21 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,if (!count) goto put_np; +if (count >1 ) { + genpd_virt_devs =kcalloc (count,sizeof (*genpd_virt_devs), +GFP_KERNEL ); +if (!genpd_virt_devs) + goto put_np; + } + required_opp_tables =kcalloc (count,sizeof (*required_opp_tables),GFP_KERNEL ); -if (!required_opp_tables) +if (!required_opp_tables) { +kfree (genpd_virt_devs); goto put_np; + } + opp_table->genpd_virt_devs = genpd_virt_devs; opp_table->required_opp_tables = required_opp_tables; opp_table->required_opp_count = count;drivers/opp/opp.h +4
-0@@ -135,6 +135,8 @@ enum opp_table_access {* @parsed_static_opps: True if OPPs are initialized from DT. * @shared_opp: OPP is shared between multiple devices. * @suspend_opp: Pointer to OPP to be used during device suspend. +* @genpd_virt_dev_lock: Mutex protecting the genpd virtual device pointers. +* @genpd_virt_devs: List of virtual devices for multiple genpd support. * @required_opp_tables: List of device OPP tables that are required by OPPs in * this table. * @required_opp_count: Number of required devices. @@ -177,6 +179,8 @@ struct opp_table {enum opp_table_access shared_opp;struct dev_pm_opp *suspend_opp; +struct mutex genpd_virt_dev_lock; +struct device **genpd_virt_devs;struct opp_table **required_opp_tables;unsigned int required_opp_count;include/linux/pm_opp.h +8
-1@@ -126,6 +126,8 @@ struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char * name);void dev_pm_opp_put_clkname (struct opp_table *opp_table);struct opp_table *dev_pm_opp_register_set_opp_helper (struct device *dev,int (*set_opp)(struct dev_pm_set_opp_data *data));void dev_pm_opp_unregister_set_opp_helper (struct opp_table *opp_table); +struct opp_table *dev_pm_opp_set_genpd_virt_dev (struct device *dev,struct device *virt_dev,int index); +void dev_pm_opp_put_genpd_virt_dev (struct opp_table *opp_table,struct device *virt_dev);int dev_pm_opp_set_rate (struct device *dev,unsigned long target_freq);int dev_pm_opp_set_sharing_cpus (struct device *cpu_dev,const struct cpumask *cpumask);int dev_pm_opp_get_sharing_cpus (struct device *cpu_dev,struct cpumask *cpumask);@@ -272,6 +274,12 @@ static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, conststatic inline void dev_pm_opp_put_clkname (struct opp_table *opp_table) {} +static inline struct opp_table *dev_pm_opp_set_genpd_virt_dev (struct device *dev,struct device *virt_dev,int index) +{ +return ERR_PTR (-ENOTSUPP ); +} + +static inline void dev_pm_opp_put_genpd_virt_dev (struct opp_table *opp_table,struct device *virt_dev) {}static inline int dev_pm_opp_set_rate (struct device *dev,unsigned long target_freq) {return -ENOTSUPP ; --2.19.1.568.g152ad8e3369a
PATCH v3 8/10 OPP: Configure all required OPPs
In reply to Viresh KumarNow that all the infrastructure is in place to support multiple required OPPs, lets switch over to using it.
A new internal routine _set_required_opps() takes care of updating performance state for all the required OPPs. With this the performance state updates are supported even when the end device needs to configure regulators as well, that wasn't the case earlier.
The pstates were earlier stored in the end device's OPP structures, that also changes now as those values are stored in the genpd's OPP structures. And so we switch over to using pm_genpd_opp_to_performance_state() instead of of_genpd_opp_to_performance_state() to get performance state for the genpd OPPs.
The routine _generic_set_opp_domain() is not required anymore and is removed.
On errors we don't try to recover by reverting to old settings as things are really complex now and the calls here should never really fail unless there is a bug. There is no point increasing the complexity, for code which will never be executed.
--- drivers/opp/core.c | 113 ++++++++++++++++++++++++++------------------- drivers/opp/of.c | 5 +- 2 files changed, 68 insertions(+), 50 deletions(-)
drivers/opp/core.c +65 -48
@@ -548,44 +548,6 @@ _generic_set_opp_clk_only(struct device *dev, struct clk *clk,return ret; } -static inline int -_generic_set_opp_domain (struct device *dev,struct clk *clk, -unsigned long old_freq,unsigned long freq, -unsigned int old_pstate,unsigned int new_pstate) -{ -int ret; - -/* Scaling up? Scale domain performance state before frequency */ -if (freq > old_freq) { - ret =dev_pm_genpd_set_performance_state (dev, new_pstate); -if (ret) -return ret; - } - - ret =_generic_set_opp_clk_only (dev, clk, old_freq, freq); -if (ret) - goto restore_domain_state; - -/* Scaling down? Scale domain performance state after frequency */ -if (freq < old_freq) { - ret =dev_pm_genpd_set_performance_state (dev, new_pstate); -if (ret) - goto restore_freq; - } - -return 0 ; - -restore_freq: -if (_generic_set_opp_clk_only (dev, clk, freq, old_freq)) -dev_err (dev,"%s: failed to restore old-freq (%lu Hz)\n" , - __func__, old_freq); -restore_domain_state: -if (freq > old_freq) -dev_pm_genpd_set_performance_state (dev, old_pstate); - -return ret; -} - static int _generic_set_opp_regulator(const struct opp_table *opp_table, struct device *dev, unsigned long old_freq,
@@ -663,6 +625,56 @@ static int _set_opp_custom(const struct opp_table *opp_table,return opp_table->set_opp (data); } +/* This is only called for PM domain for now */ +static int _set_required_opps (struct device *dev, +struct opp_table *opp_table, +struct dev_pm_opp *opp) +{ +struct opp_table **required_opp_tables = opp_table->required_opp_tables; +struct device **genpd_virt_devs = opp_table->genpd_virt_devs; +unsigned int pstate; +int i, ret =0 ; + +if (!required_opp_tables) +return 0 ; + +/* Single genpd case */ +if (!genpd_virt_devs) { + pstate = opp->required_opps[0 ]->pstate; + ret =dev_pm_genpd_set_performance_state (dev, pstate); +if (ret) { +dev_err (dev,"Failed to set performance state of %s: %d (%d)\n" , +dev_name (dev), pstate, ret); + } +return ret; + } + +/* Multiple genpd case */ + +/* +* Acquire genpd_virt_dev_lock to make sure we don't use a genpd_dev +* after it is freed from another thread. +*/ +mutex_lock (&opp_table->genpd_virt_dev_lock); + +for (i =0 ; i < opp_table->required_opp_count; i++) { + pstate = opp->required_opps[i]->pstate; + +if (!genpd_virt_devs[i]) +continue ; + + ret =dev_pm_genpd_set_performance_state (genpd_virt_devs[i], pstate); +if (ret) { +dev_err (dev,"Failed to set performance rate of %s: %d (%d)\n" , +dev_name (genpd_virt_devs[i]), pstate, ret); +break ; + } + } +mutex_unlock (&opp_table->genpd_virt_dev_lock); + +return ret; +} +/** * dev_pm_opp_set_rate() - Configure new OPP based on frequency * @dev: device for which we do this operation
@@ -730,6 +742,13 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)dev_dbg (dev,"%s: switching OPP: %lu Hz --> %lu Hz\n" , __func__, old_freq, freq); +/* Scaling up? Configure required OPPs before frequency */ +if (freq > old_freq) { + ret =_set_required_opps (dev, opp_table, opp); +if (ret) + goto put_opp; + } +if (opp_table->set_opp) { ret = _set_opp_custom(opp_table, dev, old_freq, freq, IS_ERR(old_opp) ? NULL : old_opp->supplies,
@@ -740,19 +759,17 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) opp->supplies); }else {/* Only frequency scaling */ + ret =_generic_set_opp_clk_only (dev, clk, old_freq, freq); + } -/* -* We don't support devices with both regulator and -* domain performance-state for now. -*/ -if (opp_table->genpd_performance_state) - ret =_generic_set_opp_domain (dev, clk, old_freq, freq, -IS_ERR (old_opp) ?0 : old_opp->pstate, - opp->pstate); -else - ret =_generic_set_opp_clk_only (dev, clk, old_freq, freq); +/* Scaling down? Configure required OPPs after frequency */ +if (!ret && freq < old_freq) { + ret =_set_required_opps (dev, opp_table, opp); +if (ret) +dev_err (dev,"Failed to set required opps: %d\n" , ret); } +put_opp:dev_pm_opp_put (opp); put_old_opp:if (!IS_ERR (old_opp))
drivers/opp/of.c +3 -2
@@ -595,12 +595,13 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,if (!of_property_read_u32 (np,"clock-latency-ns" , &val)) new_opp->clock_latency_ns = val; - new_opp->pstate =of_genpd_opp_to_performance_state (dev, np); - ret =opp_parse_supplies (new_opp, dev, opp_table);if (ret) goto free_required_opps; +if (opp_table->is_genpd) + new_opp->pstate =pm_genpd_opp_to_performance_state (dev, new_opp); + ret =_opp_add (dev, new_opp, opp_table, rate_not_available);if (ret) {/* Don't return error for duplicate OPPs */
Signature · 1 line
2.19.1.568.g152ad8e3369a
Re: [PATCH V3 08/10] OPP: Configure all required OPPs
Quoted 18 lines · Viresh Kumar
Now that all the infrastructure is in place to support multiple required OPPs, lets switch over to using it.
A new internal routine
_set_required_opps()takes care of updating performance state for all the required OPPs. With this the performance state updates are supported even when the end device needs to configure regulators as well, that wasn't the case earlier.The pstates were earlier stored in the end device's OPP structures, that also changes now as those values are stored in the genpd's OPP structures. And so we switch over to using
pm_genpd_opp_to_performance_state()instead ofof_genpd_opp_to_performance_state()to get performance state for the genpd OPPs.The routine
_generic_set_opp_domain()is not required anymore and is removed.
Quoted 6 lines
On errors we don't try to recover by reverting to old settings as things are really complex now and the calls here should never really fail unless there is a bug. There is no point increasing the complexity, for code which will never be executed.
Signed-off-by Viresh Kumar <[email protected]>
Kind regards
Uffe
Quoted 176 lines
--- drivers/opp/core.c | 113 ++++++++++++++++++++++++++------------------- drivers/opp/of.c | 5 +- 2 files changed, 68 insertions(+), 50 deletions(-)drivers/opp/core.c +65
-48@@ -548,44 +548,6 @@ _generic_set_opp_clk_only(struct device *dev, struct clk *clk,return ret; } -static inline int -_generic_set_opp_domain (struct device *dev,struct clk *clk, -unsigned long old_freq,unsigned long freq, -unsigned int old_pstate,unsigned int new_pstate) -{ -int ret; - -/* Scaling up? Scale domain performance state before frequency */ -if (freq > old_freq) { - ret =dev_pm_genpd_set_performance_state (dev, new_pstate); -if (ret) -return ret; - } - - ret =_generic_set_opp_clk_only (dev, clk, old_freq, freq); -if (ret) - goto restore_domain_state; - -/* Scaling down? Scale domain performance state after frequency */ -if (freq < old_freq) { - ret =dev_pm_genpd_set_performance_state (dev, new_pstate); -if (ret) - goto restore_freq; - } - -return 0 ; - -restore_freq: -if (_generic_set_opp_clk_only (dev, clk, freq, old_freq)) -dev_err (dev,"%s: failed to restore old-freq (%lu Hz)\n" , - __func__, old_freq); -restore_domain_state: -if (freq > old_freq) -dev_pm_genpd_set_performance_state (dev, old_pstate); - -return ret; -} - static int _generic_set_opp_regulator(const struct opp_table *opp_table, struct device *dev, unsigned long old_freq,@@ -663,6 +625,56 @@ static int _set_opp_custom(const struct opp_table *opp_table,return opp_table->set_opp (data); } +/* This is only called for PM domain for now */ +static int _set_required_opps (struct device *dev, +struct opp_table *opp_table, +struct dev_pm_opp *opp) +{ +struct opp_table **required_opp_tables = opp_table->required_opp_tables; +struct device **genpd_virt_devs = opp_table->genpd_virt_devs; +unsigned int pstate; +int i, ret =0 ; + +if (!required_opp_tables) +return 0 ; + +/* Single genpd case */ +if (!genpd_virt_devs) { + pstate = opp->required_opps[0 ]->pstate; + ret =dev_pm_genpd_set_performance_state (dev, pstate); +if (ret) { +dev_err (dev,"Failed to set performance state of %s: %d (%d)\n" , +dev_name (dev), pstate, ret); + } +return ret; + } + +/* Multiple genpd case */ + +/* +* Acquire genpd_virt_dev_lock to make sure we don't use a genpd_dev +* after it is freed from another thread. +*/ +mutex_lock (&opp_table->genpd_virt_dev_lock); + +for (i =0 ; i < opp_table->required_opp_count; i++) { + pstate = opp->required_opps[i]->pstate; + +if (!genpd_virt_devs[i]) +continue ; + + ret =dev_pm_genpd_set_performance_state (genpd_virt_devs[i], pstate); +if (ret) { +dev_err (dev,"Failed to set performance rate of %s: %d (%d)\n" , +dev_name (genpd_virt_devs[i]), pstate, ret); +break ; + } + } +mutex_unlock (&opp_table->genpd_virt_dev_lock); + +return ret; +} +/** * dev_pm_opp_set_rate() - Configure new OPP based on frequency * @dev: device for which we do this operation @@ -730,6 +742,13 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)dev_dbg (dev,"%s: switching OPP: %lu Hz --> %lu Hz\n" , __func__, old_freq, freq); +/* Scaling up? Configure required OPPs before frequency */ +if (freq > old_freq) { + ret =_set_required_opps (dev, opp_table, opp); +if (ret) + goto put_opp; + } +if (opp_table->set_opp) { ret = _set_opp_custom(opp_table, dev, old_freq, freq, IS_ERR(old_opp) ? NULL : old_opp->supplies,@@ -740,19 +759,17 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) opp->supplies); }else {/* Only frequency scaling */ + ret =_generic_set_opp_clk_only (dev, clk, old_freq, freq); + } -/* -* We don't support devices with both regulator and -* domain performance-state for now. -*/ -if (opp_table->genpd_performance_state) - ret =_generic_set_opp_domain (dev, clk, old_freq, freq, -IS_ERR (old_opp) ?0 : old_opp->pstate, - opp->pstate); -else - ret =_generic_set_opp_clk_only (dev, clk, old_freq, freq); +/* Scaling down? Configure required OPPs after frequency */ +if (!ret && freq < old_freq) { + ret =_set_required_opps (dev, opp_table, opp); +if (ret) +dev_err (dev,"Failed to set required opps: %d\n" , ret); } +put_opp:dev_pm_opp_put (opp); put_old_opp:if (!IS_ERR (old_opp))drivers/opp/of.c +3
-3@@ -595,12 +595,13 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,if (!of_property_read_u32 (np,"clock-latency-ns" , &val)) new_opp->clock_latency_ns = val; - new_opp->pstate =of_genpd_opp_to_performance_state (dev, np); - ret =opp_parse_supplies (new_opp, dev, opp_table);if (ret) goto free_required_opps; +if (opp_table->is_genpd) + new_opp->pstate =pm_genpd_opp_to_performance_state (dev, new_opp); + ret =_opp_add (dev, new_opp, opp_table, rate_not_available);if (ret) {/* Don't return error for duplicate OPPs */ --2.19.1.568.g152ad8e3369a
PATCH v3 9/10 OPP: Rename and relocate of_genpd_opp_to_performance_state()
In reply to Viresh KumarThe OPP core already has the performance state values for each of the genpd's OPPs and there is no need to call the genpd callback again to get the performance state for the case where the end device doesn't have an OPP table and has the "required-opps" property directly in its node.
This commit renames of_genpd_opp_to_performance_state() as of_get_required_opp_performance_state() and moves it to the OPP core, as it is all about OPP stuff now.
--- drivers/base/power/domain.c | 48 ------------------------------------- drivers/opp/of.c | 44 ++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 9 ------- include/linux/pm_opp.h | 5 ++++ 4 files changed, 49 insertions(+), 57 deletions(-)
drivers/base/power/domain.c +0 -48
@@ -2552,54 +2552,6 @@ unsigned int pm_genpd_opp_to_performance_state(struct device *genpd_dev, }EXPORT_SYMBOL_GPL (pm_genpd_opp_to_performance_state); -/** -* of_genpd_opp_to_performance_state- Gets performance state of device's -* power domain corresponding to a DT node's "required-opps" property. -* -* @dev: Device for which the performance-state needs to be found. -* @np: DT node where the "required-opps" property is present. This can be -* the device node itself (if it doesn't have an OPP table) or a node -* within the OPP table of a device (if device has an OPP table). -* -* Returns performance state corresponding to the "required-opps" property of -* a DT node. This calls platform specific genpd->opp_to_performance_state() -* callback to translate power domain OPP to performance state. -* -* Returns performance state on success and 0 on failure. -*/ -unsigned int of_genpd_opp_to_performance_state (struct device *dev, -struct device_node *np) -{ -struct generic_pm_domain *genpd; -struct dev_pm_opp *opp; -int state =0 ; - - genpd =dev_to_genpd (dev); -if (IS_ERR (genpd)) -return 0 ; - -if (unlikely (!genpd->set_performance_state)) -return 0 ; - -genpd_lock (genpd); - - opp =of_dev_pm_opp_find_required_opp (&genpd->dev, np); -if (IS_ERR (opp)) { -dev_err (dev,"Failed to find required OPP: %ld\n" , -PTR_ERR (opp)); - goto unlock; - } - - state = genpd->opp_to_performance_state (genpd, opp); -dev_pm_opp_put (opp); - -unlock: -genpd_unlock (genpd); - -return state; -} -EXPORT_SYMBOL_GPL (of_genpd_opp_to_performance_state); -static int __init genpd_bus_init (void ) {return bus_register (&genpd_bus_type);
drivers/opp/of.c +44 -0
50 lines not on this page · raw message
include/linux/pm_domain.h +0 -9
@@ -260,8 +260,6 @@ int of_genpd_parse_idle_states(struct device_node *dn, struct genpd_power_state **states, int *n);unsigned int pm_genpd_opp_to_performance_state (struct device *genpd_dev,struct dev_pm_opp *opp); -unsigned int of_genpd_opp_to_performance_state (struct device *dev, -struct device_node *np);int genpd_dev_pm_attach (struct device *dev); struct device *genpd_dev_pm_attach_by_id(struct device *dev,
@@ -308,13 +306,6 @@ pm_genpd_opp_to_performance_state(struct device *genpd_dev,return 0 ; } -static inline unsigned int -of_genpd_opp_to_performance_state (struct device *dev, -struct device_node *np) -{ -return 0 ; -} -static inline int genpd_dev_pm_attach (struct device *dev) {return 0 ;
include/linux/pm_opp.h +5 -0
@@ -315,6 +315,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumastruct device_node *dev_pm_opp_of_get_opp_desc_node (struct device *dev);struct dev_pm_opp *of_dev_pm_opp_find_required_opp (struct device *dev,struct device_node *np);struct device_node *dev_pm_opp_get_of_node (struct dev_pm_opp *opp); +unsigned int of_get_required_opp_performance_state (struct device_node *np,int index);#else static inline int dev_pm_opp_of_add_table (struct device *dev) {
@@ -357,6 +358,10 @@ static inline struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp) {return NULL ; } +static inline unsigned int of_get_required_opp_performance_state (struct device_node *np,int index) +{ +return 0 ; +}#endif #endif /* __LINUX_OPP_H__ */
Signature · 1 line
2.19.1.568.g152ad8e3369a
Re: [PATCH V3 09/10] OPP: Rename and relocate of_genpd_opp_to_performance_state()
Quoted 10 lines · Viresh Kumar
The OPP core already has the performance state values for each of the genpd's OPPs and there is no need to call the genpd callback again to get the performance state for the case where the end device doesn't have an OPP table and has the "required-opps" property directly in its node.
This commit renames
of_genpd_opp_to_performance_state()asof_get_required_opp_performance_state()and moves it to the OPP core, as it is all about OPP stuff now.Signed-off-by Viresh Kumar <[email protected]>
Kind regards
Uffe
Quoted 174 lines
--- drivers/base/power/domain.c | 48 ------------------------------------- drivers/opp/of.c | 44 ++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 9 ------- include/linux/pm_opp.h | 5 ++++ 4 files changed, 49 insertions(+), 57 deletions(-)drivers/base/power/domain.c +0
-48@@ -2552,54 +2552,6 @@ unsigned int pm_genpd_opp_to_performance_state(struct device *genpd_dev, }EXPORT_SYMBOL_GPL (pm_genpd_opp_to_performance_state); -/** -* of_genpd_opp_to_performance_state- Gets performance state of device's -* power domain corresponding to a DT node's "required-opps" property. -* -* @dev: Device for which the performance-state needs to be found. -* @np: DT node where the "required-opps" property is present. This can be -* the device node itself (if it doesn't have an OPP table) or a node -* within the OPP table of a device (if device has an OPP table). -* -* Returns performance state corresponding to the "required-opps" property of -* a DT node. This calls platform specific genpd->opp_to_performance_state() -* callback to translate power domain OPP to performance state. -* -* Returns performance state on success and 0 on failure. -*/ -unsigned int of_genpd_opp_to_performance_state (struct device *dev, -struct device_node *np) -{ -struct generic_pm_domain *genpd; -struct dev_pm_opp *opp; -int state =0 ; - - genpd =dev_to_genpd (dev); -if (IS_ERR (genpd)) -return 0 ; - -if (unlikely (!genpd->set_performance_state)) -return 0 ; - -genpd_lock (genpd); - - opp =of_dev_pm_opp_find_required_opp (&genpd->dev, np); -if (IS_ERR (opp)) { -dev_err (dev,"Failed to find required OPP: %ld\n" , -PTR_ERR (opp)); - goto unlock; - } - - state = genpd->opp_to_performance_state (genpd, opp); -dev_pm_opp_put (opp); - -unlock: -genpd_unlock (genpd); - -return state; -} -EXPORT_SYMBOL_GPL (of_genpd_opp_to_performance_state); -static int __init genpd_bus_init (void ) {return bus_register (&genpd_bus_type);drivers/opp/of.c +44
-0@@ -969,6 +969,50 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, }EXPORT_SYMBOL_GPL (dev_pm_opp_of_get_sharing_cpus); +/** +* of_get_required_opp_performance_state() - Search for required OPP and return its performance state. +* @np: Node that contains the "required-opps" property. +* @index: Index of the phandle to parse. +* +* Returns the performance state of the OPP pointed out by the "required-opps" +* property at @index in @np. +* +* Return: Positive performance state on success, otherwise 0 on errors. +*/ +unsigned int of_get_required_opp_performance_state (struct device_node *np, +int index) +{ +struct dev_pm_opp *opp; +struct device_node *required_np; +struct opp_table *opp_table; +unsigned int pstate =0 ; + + required_np =of_parse_required_opp (np, index); +if (!required_np) +return -ENODEV ; + + opp_table =_find_table_of_opp_np (required_np); +if (IS_ERR (opp_table)) { +pr_err ("%s: Failed to find required OPP table %pOF: %ld\n" , + __func__, np,PTR_ERR (opp_table)); + goto put_required_np; + } + + opp =_find_opp_of_np (opp_table, required_np); +if (opp) { + pstate = opp->pstate; +dev_pm_opp_put (opp); + } + +dev_pm_opp_put_opp_table (opp_table); + +put_required_np: +of_node_put (required_np); + +return pstate; +} +EXPORT_SYMBOL_GPL (of_get_required_opp_performance_state); +/** * of_dev_pm_opp_find_required_opp() - Search for required OPP. * @dev: The device whose OPP node is referenced by the 'np' DT node. include/linux/pm_domain.h +0
-9@@ -260,8 +260,6 @@ int of_genpd_parse_idle_states(struct device_node *dn, struct genpd_power_state **states, int *n);unsigned int pm_genpd_opp_to_performance_state (struct device *genpd_dev,struct dev_pm_opp *opp); -unsigned int of_genpd_opp_to_performance_state (struct device *dev, -struct device_node *np);int genpd_dev_pm_attach (struct device *dev); struct device *genpd_dev_pm_attach_by_id(struct device *dev,@@ -308,13 +306,6 @@ pm_genpd_opp_to_performance_state(struct device *genpd_dev,return 0 ; } -static inline unsigned int -of_genpd_opp_to_performance_state (struct device *dev, -struct device_node *np) -{ -return 0 ; -} -static inline int genpd_dev_pm_attach (struct device *dev) {return 0 ;include/linux/pm_opp.h +5
-1@@ -315,6 +315,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumastruct device_node *dev_pm_opp_of_get_opp_desc_node (struct device *dev);struct dev_pm_opp *of_dev_pm_opp_find_required_opp (struct device *dev,struct device_node *np);struct device_node *dev_pm_opp_get_of_node (struct dev_pm_opp *opp); +unsigned int of_get_required_opp_performance_state (struct device_node *np,int index);#else static inline int dev_pm_opp_of_add_table (struct device *dev) {@@ -357,6 +358,10 @@ static inline struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp) {return NULL ; } +static inline unsigned int of_get_required_opp_performance_state (struct device_node *np,int index) +{ +return 0 ; +}#endif #endif /* __LINUX_OPP_H__ */ --2.19.1.568.g152ad8e3369a
PATCH v4 9/10 OPP: Rename and relocate of_genpd_opp_to_performance_state()
In reply to Viresh KumarThe OPP core already has the performance state values for each of the genpd's OPPs and there is no need to call the genpd callback again to get the performance state for the case where the end device doesn't have an OPP table and has the "required-opps" property directly in its node.
This commit renames of_genpd_opp_to_performance_state() as of_get_required_opp_performance_state() and moves it to the OPP core, as it is all about OPP stuff now.
---V3->V4:
- Return 0 from of_get_required_opp_performance_state() on error instead of -ENODEV as described by the comment over the helper.
- Add Reviewed by tag from Ulf.
drivers/base/power/domain.c | 48 ------------------------------------- drivers/opp/of.c | 44 ++++++++++++++++++++++++++++++++++ include/linux/pm_domain.h | 9 ------- include/linux/pm_opp.h | 5 ++++ 4 files changed, 49 insertions(+), 57 deletions(-)
drivers/base/power/domain.c +0 -48
@@ -2552,54 +2552,6 @@ unsigned int pm_genpd_opp_to_performance_state(struct device *genpd_dev, }EXPORT_SYMBOL_GPL (pm_genpd_opp_to_performance_state); -/** -* of_genpd_opp_to_performance_state- Gets performance state of device's -* power domain corresponding to a DT node's "required-opps" property. -* -* @dev: Device for which the performance-state needs to be found. -* @np: DT node where the "required-opps" property is present. This can be -* the device node itself (if it doesn't have an OPP table) or a node -* within the OPP table of a device (if device has an OPP table). -* -* Returns performance state corresponding to the "required-opps" property of -* a DT node. This calls platform specific genpd->opp_to_performance_state() -* callback to translate power domain OPP to performance state. -* -* Returns performance state on success and 0 on failure. -*/ -unsigned int of_genpd_opp_to_performance_state (struct device *dev, -struct device_node *np) -{ -struct generic_pm_domain *genpd; -struct dev_pm_opp *opp; -int state =0 ; - - genpd =dev_to_genpd (dev); -if (IS_ERR (genpd)) -return 0 ; - -if (unlikely (!genpd->set_performance_state)) -return 0 ; - -genpd_lock (genpd); - - opp =of_dev_pm_opp_find_required_opp (&genpd->dev, np); -if (IS_ERR (opp)) { -dev_err (dev,"Failed to find required OPP: %ld\n" , -PTR_ERR (opp)); - goto unlock; - } - - state = genpd->opp_to_performance_state (genpd, opp); -dev_pm_opp_put (opp); - -unlock: -genpd_unlock (genpd); - -return state; -} -EXPORT_SYMBOL_GPL (of_genpd_opp_to_performance_state); -static int __init genpd_bus_init (void ) {return bus_register (&genpd_bus_type);
drivers/opp/of.c +44 -0
50 lines not on this page · raw message
include/linux/pm_domain.h +0 -9
@@ -260,8 +260,6 @@ int of_genpd_parse_idle_states(struct device_node *dn, struct genpd_power_state **states, int *n);unsigned int pm_genpd_opp_to_performance_state (struct device *genpd_dev,struct dev_pm_opp *opp); -unsigned int of_genpd_opp_to_performance_state (struct device *dev, -struct device_node *np);int genpd_dev_pm_attach (struct device *dev); struct device *genpd_dev_pm_attach_by_id(struct device *dev,
@@ -308,13 +306,6 @@ pm_genpd_opp_to_performance_state(struct device *genpd_dev,return 0 ; } -static inline unsigned int -of_genpd_opp_to_performance_state (struct device *dev, -struct device_node *np) -{ -return 0 ; -} -static inline int genpd_dev_pm_attach (struct device *dev) {return 0 ;
include/linux/pm_opp.h +5 -0
@@ -315,6 +315,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumastruct device_node *dev_pm_opp_of_get_opp_desc_node (struct device *dev);struct dev_pm_opp *of_dev_pm_opp_find_required_opp (struct device *dev,struct device_node *np);struct device_node *dev_pm_opp_get_of_node (struct dev_pm_opp *opp); +unsigned int of_get_required_opp_performance_state (struct device_node *np,int index);#else static inline int dev_pm_opp_of_add_table (struct device *dev) {
@@ -357,6 +358,10 @@ static inline struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp) {return NULL ; } +static inline unsigned int of_get_required_opp_performance_state (struct device_node *np,int index) +{ +return 0 ; +}#endif #endif /* __LINUX_OPP_H__ */
Signature · 1 line
2.19.1.568.g152ad8e3369a
PATCH v3 10/10 OPP: Remove of_dev_pm_opp_find_required_opp()
In reply to Viresh KumarThis isn't used anymore, remove it.
--- drivers/opp/of.c | 54 ------------------------------------------ include/linux/pm_opp.h | 5 ---- 2 files changed, 59 deletions(-)
drivers/opp/of.c +0 -54
@@ -1013,60 +1013,6 @@ unsigned int of_get_required_opp_performance_state(struct device_node *np, }EXPORT_SYMBOL_GPL (of_get_required_opp_performance_state); -/** -* of_dev_pm_opp_find_required_opp() - Search for required OPP. -* @dev: The device whose OPP node is referenced by the 'np' DT node. -* @np: Node that contains the "required-opps" property. -* -* Returns the OPP of the device 'dev', whose phandle is present in the "np" -* node. Although the "required-opps" property supports having multiple -* phandles, this helper routine only parses the very first phandle in the list. -* -* Return: Matching opp, else returns ERR_PTR in case of error and should be -* handled using IS_ERR. -* -* The callers are required to call dev_pm_opp_put() for the returned OPP after -* use. -*/ -struct dev_pm_opp *of_dev_pm_opp_find_required_opp (struct device *dev, -struct device_node *np) -{ -struct dev_pm_opp *temp_opp, *opp =ERR_PTR (-ENODEV ); -struct device_node *required_np; -struct opp_table *opp_table; - - opp_table =_find_opp_table (dev); -if (IS_ERR (opp_table)) -return ERR_CAST (opp_table); - - required_np =of_parse_phandle (np,"required-opps" ,0 ); -if (unlikely (!required_np)) { -dev_err (dev,"Unable to parse required-opps\n" ); - goto put_opp_table; - } - -mutex_lock (&opp_table->lock); - -list_for_each_entry (temp_opp, &opp_table->opp_list, node) { -if (temp_opp->available && temp_opp->np == required_np) { - opp = temp_opp; - -/* Increment the reference count of OPP */ -dev_pm_opp_get (opp); -break ; - } - } - -mutex_unlock (&opp_table->lock); - -of_node_put (required_np); -put_opp_table: -dev_pm_opp_put_opp_table (opp_table); - -return opp; -} -EXPORT_SYMBOL_GPL (of_dev_pm_opp_find_required_opp); -/** * dev_pm_opp_get_of_node() - Gets the DT node corresponding to an opp * @opp: opp for which DT node has to be returned for
include/linux/pm_opp.h +0 -5
@@ -313,7 +313,6 @@ int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask);void dev_pm_opp_of_cpumask_remove_table (const struct cpumask *cpumask);int dev_pm_opp_of_get_sharing_cpus (struct device *cpu_dev,struct cpumask *cpumask);struct device_node *dev_pm_opp_of_get_opp_desc_node (struct device *dev); -struct dev_pm_opp *of_dev_pm_opp_find_required_opp (struct device *dev,struct device_node *np);struct device_node *dev_pm_opp_get_of_node (struct dev_pm_opp *opp);unsigned int of_get_required_opp_performance_state (struct device_node *np,int index);#else
@@ -350,10 +349,6 @@ static inline struct device_node *dev_pm_opp_of_get_opp_desc_node(struct devicereturn NULL ; } -static inline struct dev_pm_opp *of_dev_pm_opp_find_required_opp (struct device *dev,struct device_node *np) -{ -return NULL ; -}static inline struct device_node *dev_pm_opp_get_of_node (struct dev_pm_opp *opp) {return NULL ;
Signature · 1 line
2.19.1.568.g152ad8e3369a
Re: [PATCH V3 10/10] OPP: Remove of_dev_pm_opp_find_required_opp()
Quoted 3 lines · Viresh Kumar
This isn't used anymore, remove it.
Signed-off-by Viresh Kumar <[email protected]>
Kind regards
Uffe
Quoted 96 lines
--- drivers/opp/of.c | 54 ------------------------------------------ include/linux/pm_opp.h | 5 ---- 2 files changed, 59 deletions(-)drivers/opp/of.c +0
-54@@ -1013,60 +1013,6 @@ unsigned int of_get_required_opp_performance_state(struct device_node *np, }EXPORT_SYMBOL_GPL (of_get_required_opp_performance_state); -/** -* of_dev_pm_opp_find_required_opp() - Search for required OPP. -* @dev: The device whose OPP node is referenced by the 'np' DT node. -* @np: Node that contains the "required-opps" property. -* -* Returns the OPP of the device 'dev', whose phandle is present in the "np" -* node. Although the "required-opps" property supports having multiple -* phandles, this helper routine only parses the very first phandle in the list. -* -* Return: Matching opp, else returns ERR_PTR in case of error and should be -* handled using IS_ERR. -* -* The callers are required to call dev_pm_opp_put() for the returned OPP after -* use. -*/ -struct dev_pm_opp *of_dev_pm_opp_find_required_opp (struct device *dev, -struct device_node *np) -{ -struct dev_pm_opp *temp_opp, *opp =ERR_PTR (-ENODEV ); -struct device_node *required_np; -struct opp_table *opp_table; - - opp_table =_find_opp_table (dev); -if (IS_ERR (opp_table)) -return ERR_CAST (opp_table); - - required_np =of_parse_phandle (np,"required-opps" ,0 ); -if (unlikely (!required_np)) { -dev_err (dev,"Unable to parse required-opps\n" ); - goto put_opp_table; - } - -mutex_lock (&opp_table->lock); - -list_for_each_entry (temp_opp, &opp_table->opp_list, node) { -if (temp_opp->available && temp_opp->np == required_np) { - opp = temp_opp; - -/* Increment the reference count of OPP */ -dev_pm_opp_get (opp); -break ; - } - } - -mutex_unlock (&opp_table->lock); - -of_node_put (required_np); -put_opp_table: -dev_pm_opp_put_opp_table (opp_table); - -return opp; -} -EXPORT_SYMBOL_GPL (of_dev_pm_opp_find_required_opp); -/** * dev_pm_opp_get_of_node() - Gets the DT node corresponding to an opp * @opp: opp for which DT node has to be returned for include/linux/pm_opp.h +0
-6@@ -313,7 +313,6 @@ int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask);void dev_pm_opp_of_cpumask_remove_table (const struct cpumask *cpumask);int dev_pm_opp_of_get_sharing_cpus (struct device *cpu_dev,struct cpumask *cpumask);struct device_node *dev_pm_opp_of_get_opp_desc_node (struct device *dev); -struct dev_pm_opp *of_dev_pm_opp_find_required_opp (struct device *dev,struct device_node *np);struct device_node *dev_pm_opp_get_of_node (struct dev_pm_opp *opp);unsigned int of_get_required_opp_performance_state (struct device_node *np,int index);#else @@ -350,10 +349,6 @@ static inline struct device_node *dev_pm_opp_of_get_opp_desc_node(struct devicereturn NULL ; } -static inline struct dev_pm_opp *of_dev_pm_opp_find_required_opp (struct device *dev,struct device_node *np) -{ -return NULL ; -}static inline struct device_node *dev_pm_opp_get_of_node (struct dev_pm_opp *opp) {return NULL ; --2.19.1.568.g152ad8e3369a