PM / OPP: Add debugfs support
Subsystems (11)
Viresh Kumar
maintainerv3 cover PM / OPP: Add debugfs support
Hi Rafael,
This is (hopefully) the last version of this patchset, all the patches are reviewed by Stephen (Many thanks for this) now and sending everything again so that you know exactly what all to apply.
This series is targeted towards exposing opp information at user space. I wasn't really sure about adding them to sysfs, as its mostly static (fixed) data and so debugfs looked to be better place.
This series starts with 3 cleanup patches, and then moves all opp stuff to a new directory, as its expanding enough now.
The last patch adds debugfs support for OPPs and works for both old and new v2 bindings.
Rebased over: pm/bleeding-edge branch.
V2-Resend->V3:
- 2/6 is a new patch
- 3/6 also modifies of_add_opp_table() now..
- Reviewed by tags from Stephen
V2->V2-Resend:
- V2 1/6 is dropped as its already merged, rest unchanged.
V1->V2:
- Moved the second patch to the top as its a fix (Dan Carpenter & Stephen).
- Also updated it to fix things properly.
- rearranged opp entry in drivers/base/power/Makefile (Stephen)
- Device-directory name also includes its parent name now, to make it more unique (Stephen).
- Migrate debugfs directory properly if unregistered for the owner device (Stephen).
Viresh Kumar (6):
PM / OPP: reuse of_parse_phandle()
PM / OPP: Rename opp init/free table routines PM / OPP: Prefix exported opp routines with dev_pm_opp_ PM / OPP: Move opp core to its own directory PM / OPP: Move cpu specific code to opp/cpu.c PM / OPP: Add debugfs support
arch/arm/mach-imx/mach-imx6q.c | 2 +-
drivers/base/power/Makefile | 2 +-
drivers/base/power/opp/Makefile | 3 +
drivers/base/power/{opp.c => opp/core.c} | 378 ++++---------------------------
drivers/base/power/opp/cpu.c | 268 ++++++++++++++++++++++
drivers/base/power/opp/debugfs.c | 217 ++++++++++++++++++
drivers/base/power/opp/opp.h | 186 +++++++++++++++
drivers/cpufreq/Makefile | 1 -
drivers/cpufreq/arm_big_little.h | 2 +-
drivers/cpufreq/arm_big_little_dt.c | 4 +-
drivers/cpufreq/cpufreq-dt.c | 10 +-
drivers/cpufreq/cpufreq_opp.c | 114 ----------
drivers/cpufreq/exynos5440-cpufreq.c | 6 +-
drivers/cpufreq/imx6q-cpufreq.c | 6 +-
drivers/cpufreq/mt8173-cpufreq.c | 6 +-
include/linux/pm_opp.h | 24 +-
16 files changed, 750 insertions(+), 479 deletions(-)
create mode 100644 drivers/base/power/opp/Makefile
rename drivers/base/power/{opp.c => opp/core.c} (79%)
create mode 100644 drivers/base/power/opp/cpu.c
create mode 100644 drivers/base/power/opp/debugfs.c
create mode 100644 drivers/base/power/opp/opp.h
delete mode 100644 drivers/cpufreq/cpufreq_opp.cSignature · 1 line
2.4.0
Viresh Kumar
maintainerPATCH v3 1/6 PM / OPP: reuse of_parse_phandle()
We already have a better API to get the opp descriptor block's node from cpu-node. Lets reuse that instead of creating our own routines for the same stuff. That cleans the code a lot.
This also kills a check we had earlier (as we are using the generic API now). Earlier we used to check if the operating-points-v2 property contained multiple phandles instead of a single phandle.
Killing this check isn't an issue because, we only parse the first entry with of_parse_phandle(). So, if a user passes multiple phandles, its really his problem :)
--- drivers/base/power/opp.c | 71 ++++++++++++------------------------------------ 1 file changed, 17 insertions(+), 54 deletions(-)
drivers/base/power/opp.c +17 -54
@@ -1253,69 +1253,33 @@ void of_cpumask_free_opp_table(cpumask_var_t cpumask) }EXPORT_SYMBOL_GPL (of_cpumask_free_opp_table); -/* Returns opp descriptor node from its phandle. Caller must do of_node_put() */ -static struct device_node * -_of_get_opp_desc_node_from_prop (struct device *dev,const struct property *prop) -{ -struct device_node *opp_np; - - opp_np =of_find_node_by_phandle (be32_to_cpup (prop->value)); -if (!opp_np) { -dev_err (dev,"%s: Prop: %s contains invalid opp desc phandle\n" , - __func__, prop->name); -return ERR_PTR (-EINVAL ); - } - -return opp_np; -} - -/* Returns opp descriptor node for a device. Caller must do of_node_put() */ +/* Returns opp descriptor node for a device, caller must do of_node_put() */ static struct device_node *_of_get_opp_desc_node (struct device *dev) { -const struct property *prop; - - prop =of_find_property (dev->of_node,"operating-points-v2" ,NULL ); -if (!prop) -return ERR_PTR (-ENODEV ); -if (!prop->value) -return ERR_PTR (-ENODATA ); -/* * TODO: Support for multiple OPP tables. * * There should be only ONE phandle present in "operating-points-v2" * property. */ -if (prop->length !=sizeof (__be32)) { -dev_err (dev,"%s: Invalid opp desc phandle\n" , __func__); -return ERR_PTR (-EINVAL ); - } -return _of_get_opp_desc_node_from_prop (dev, prop); +return of_parse_phandle (dev->of_node,"operating-points-v2" ,0 ); }/* Initializes OPP tables based on new bindings */ static int _of_init_opp_table_v2 (struct device *dev, -const struct property *prop) +struct device_node *opp_np) { -struct device_node *opp_np, *np; +struct device_node *np;struct device_opp *dev_opp;int ret =0 , count =0 ; -if (!prop->value) -return -ENODATA ; - -/* Get opp node */ - opp_np =_of_get_opp_desc_node_from_prop (dev, prop); -if (IS_ERR (opp_np)) -return PTR_ERR (opp_np); - dev_opp =_managed_opp (opp_np);if (dev_opp) {/* OPPs are already managed */ if (!_add_list_dev (dev, dev_opp)) ret = -ENOMEM ; - goto put_opp_np; +return ret; }/* We have opp-list node now, iterate over it and add OPPs */
@@ -1331,10 +1295,8 @@ static int _of_init_opp_table_v2(struct device *dev, }/* There should be one of more OPP defined */ -if (WARN_ON (!count)) { - ret = -ENOENT ; - goto put_opp_np; - } +if (WARN_ON (!count)) +return -ENOENT ; dev_opp =_find_device_opp (dev);if (WARN_ON (IS_ERR (dev_opp))) {
@@ -1345,13 +1307,10 @@ static int _of_init_opp_table_v2(struct device *dev, dev_opp->np = opp_np; dev_opp->shared_opp =of_property_read_bool (opp_np,"opp-shared" ); -of_node_put (opp_np);return 0 ; free_table:of_free_opp_table (dev); -put_opp_np: -of_node_put (opp_np);return ret; }
@@ -1418,14 +1377,15 @@ static int _of_init_opp_table_v1(struct device *dev)*/ int of_init_opp_table (struct device *dev) { -const struct property *prop; +struct device_node *opp_np; +int ret;/* * OPPs have two version of bindings now. The older one is deprecated, * try for the new binding first. */ - prop =of_find_property (dev->of_node,"operating-points-v2" ,NULL ); -if (!prop) { + opp_np =_of_get_opp_desc_node (dev); +if (!opp_np) {/* * Try old-deprecated bindings for backward compatibility with * older dtbs.
@@ -1433,7 +1393,10 @@ int of_init_opp_table(struct device *dev)return _of_init_opp_table_v1 (dev); } -return _of_init_opp_table_v2 (dev, prop); + ret =_of_init_opp_table_v2 (dev, opp_np); +of_node_put (opp_np); + +return ret; }EXPORT_SYMBOL_GPL (of_init_opp_table);
@@ -1522,7 +1485,7 @@ int of_get_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask)/* Get OPP descriptor node */ np =_of_get_opp_desc_node (cpu_dev); -if (IS_ERR (np)) { +if (!np) {dev_dbg (cpu_dev,"%s: Couldn't find opp node: %ld\n" , __func__,PTR_ERR (np));return -ENOENT ;
@@ -1546,7 +1509,7 @@ int of_get_cpus_sharing_opps(struct device *cpu_dev, cpumask_var_t cpumask)/* Get OPP descriptor node */ tmp_np =_of_get_opp_desc_node (tcpu_dev); -if (IS_ERR (tmp_np)) { +if (!tmp_np) {dev_err (tcpu_dev,"%s: Couldn't find opp node: %ld\n" , __func__,PTR_ERR (tmp_np)); ret =PTR_ERR (tmp_np);
Signature · 1 line
2.4.0
Viresh Kumar
maintainerPATCH v3 2/6 PM / OPP: Rename opp init/free table routines
In reply to Viresh Kumarfree-table routines are opposite of init-table ones, and must be named to make that clear. Opposite of 'init' is 'exit', but those doesn't suit really well.
Replace 'init' with 'add' and 'free' with 'remove'.
--- arch/arm/mach-imx/mach-imx6q.c | 2 +- drivers/base/power/opp.c | 41 ++++++++++++++++++------------------ drivers/cpufreq/arm_big_little.h | 2 +- drivers/cpufreq/arm_big_little_dt.c | 4 ++-- drivers/cpufreq/cpufreq-dt.c | 6 +++--- drivers/cpufreq/exynos5440-cpufreq.c | 6 +++--- drivers/cpufreq/imx6q-cpufreq.c | 6 +++--- drivers/cpufreq/mt8173-cpufreq.c | 6 +++--- include/linux/pm_opp.h | 16 +++++++------- 9 files changed, 44 insertions(+), 45 deletions(-)
arch/arm/mach-imx/mach-imx6q.c +1 -1
@@ -350,7 +350,7 @@ static void __init imx6q_opp_init(void)return ; } -if (of_init_opp_table (cpu_dev)) { +if (of_add_opp_table (cpu_dev)) {pr_warn ("failed to init OPP table\n" ); goto put_node; }
drivers/base/power/opp.c +20 -21
133 lines not on this page · raw message
drivers/cpufreq/arm_big_little.h +1 -1
@@ -28,7 +28,7 @@ struct cpufreq_arm_bL_ops {/* * This must set opp table for cpu_dev in a similar way as done by -* of_init_opp_table(). +* of_add_opp_table(). */ int (*init_opp_table)(struct device *cpu_dev);
drivers/cpufreq/arm_big_little_dt.c +2 -2
@@ -54,7 +54,7 @@ static int dt_init_opp_table(struct device *cpu_dev)return -ENOENT ; } - ret =of_init_opp_table (cpu_dev); + ret =of_add_opp_table (cpu_dev);of_node_put (np);return ret;
@@ -82,7 +82,7 @@ static struct cpufreq_arm_bL_ops dt_bL_ops = { .name = "dt-bl", .get_transition_latency = dt_get_transition_latency, .init_opp_table = dt_init_opp_table, - .free_opp_table = of_free_opp_table, + .free_opp_table = of_remove_opp_table, };static int generic_bL_probe (struct platform_device *pdev)
drivers/cpufreq/cpufreq-dt.c +3 -3
@@ -237,7 +237,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)* * OPPs might be populated at runtime, don't check for error here */ -of_cpumask_init_opp_table (policy->cpus); +of_cpumask_add_opp_table (policy->cpus);/* * But we need OPP table to function so if it is not there let's
@@ -360,7 +360,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) out_free_priv:kfree (priv); out_free_opp: -of_cpumask_free_opp_table (policy->cpus); +of_cpumask_remove_opp_table (policy->cpus); out_node_put:of_node_put (np); out_put_reg_clk:
@@ -377,7 +377,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy)cpufreq_cooling_unregister (priv->cdev);dev_pm_opp_free_cpufreq_table (priv->cpu_dev, &policy->freq_table); -of_cpumask_free_opp_table (policy->related_cpus); +of_cpumask_remove_opp_table (policy->related_cpus);clk_put (policy->clk);if (!IS_ERR (priv->cpu_reg))regulator_put (priv->cpu_reg);
drivers/cpufreq/exynos5440-cpufreq.c +3 -3
@@ -360,7 +360,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) goto err_put_node; } - ret =of_init_opp_table (dvfs_info->dev); + ret =of_add_opp_table (dvfs_info->dev);if (ret) {dev_err (dvfs_info->dev,"failed to init OPP table: %d\n" , ret); goto err_put_node;
@@ -424,7 +424,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) err_free_table:dev_pm_opp_free_cpufreq_table (dvfs_info->dev, &dvfs_info->freq_table); err_free_opp: -of_free_opp_table (dvfs_info->dev); +of_remove_opp_table (dvfs_info->dev); err_put_node:of_node_put (np);dev_err (&pdev->dev,"%s: failed initialization\n" , __func__);
@@ -435,7 +435,7 @@ static int exynos_cpufreq_remove(struct platform_device *pdev) {cpufreq_unregister_driver (&exynos_driver);dev_pm_opp_free_cpufreq_table (dvfs_info->dev, &dvfs_info->freq_table); -of_free_opp_table (dvfs_info->dev); +of_remove_opp_table (dvfs_info->dev);return 0 ; }
drivers/cpufreq/imx6q-cpufreq.c +3 -3
@@ -202,7 +202,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)*/ num =dev_pm_opp_get_opp_count (cpu_dev);if (num <0 ) { - ret =of_init_opp_table (cpu_dev); + ret =of_add_opp_table (cpu_dev);if (ret <0 ) {dev_err (cpu_dev,"failed to init OPP table: %d\n" , ret); goto put_reg;
@@ -312,7 +312,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)dev_pm_opp_free_cpufreq_table (cpu_dev, &freq_table); out_free_opp:if (free_opp) -of_free_opp_table (cpu_dev); +of_remove_opp_table (cpu_dev); put_reg:if (!IS_ERR (arm_reg))regulator_put (arm_reg);
@@ -340,7 +340,7 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev)cpufreq_unregister_driver (&imx6q_cpufreq_driver);dev_pm_opp_free_cpufreq_table (cpu_dev, &freq_table);if (free_opp) -of_free_opp_table (cpu_dev); +of_remove_opp_table (cpu_dev);regulator_put (arm_reg);if (!IS_ERR (pu_reg))regulator_put (pu_reg);
drivers/cpufreq/mt8173-cpufreq.c +3 -3
@@ -344,7 +344,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)/* Both presence and absence of sram regulator are valid cases. */ sram_reg =regulator_get_exclusive (cpu_dev,"sram" ); - ret =of_init_opp_table (cpu_dev); + ret =of_add_opp_table (cpu_dev);if (ret) {pr_warn ("no OPP table for cpu%d\n" , cpu); goto out_free_resources;
@@ -378,7 +378,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)return 0 ; out_free_opp_table: -of_free_opp_table (cpu_dev); +of_remove_opp_table (cpu_dev); out_free_resources:if (!IS_ERR (proc_reg))
@@ -404,7 +404,7 @@ static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)if (!IS_ERR (info->inter_clk))clk_put (info->inter_clk); -of_free_opp_table (info->cpu_dev); +of_remove_opp_table (info->cpu_dev); }static int mtk_cpufreq_init (struct cpufreq_policy *policy)
include/linux/pm_opp.h +8 -8
@@ -126,28 +126,28 @@ static inline struct srcu_notifier_head *dev_pm_opp_get_notifier(#endif /* CONFIG_PM_OPP */ #if defined(CONFIG_PM_OPP ) && defined(CONFIG_OF ) -int of_init_opp_table (struct device *dev); -void of_free_opp_table (struct device *dev); -int of_cpumask_init_opp_table (cpumask_var_t cpumask); -void of_cpumask_free_opp_table (cpumask_var_t cpumask); +int of_add_opp_table (struct device *dev); +void of_remove_opp_table (struct device *dev); +int of_cpumask_add_opp_table (cpumask_var_t cpumask); +void of_cpumask_remove_opp_table (cpumask_var_t cpumask);int of_get_cpus_sharing_opps (struct device *cpu_dev,cpumask_var_t cpumask);int set_cpus_sharing_opps (struct device *cpu_dev,cpumask_var_t cpumask);#else -static inline int of_init_opp_table (struct device *dev) +static inline int of_add_opp_table (struct device *dev) {return -EINVAL ; } -static inline void of_free_opp_table (struct device *dev) +static inline void of_remove_opp_table (struct device *dev) { } -static inline int of_cpumask_init_opp_table (cpumask_var_t cpumask) +static inline int of_cpumask_add_opp_table (cpumask_var_t cpumask) {return -ENOSYS ; } -static inline void of_cpumask_free_opp_table (cpumask_var_t cpumask) +static inline void of_cpumask_remove_opp_table (cpumask_var_t cpumask) { }
Signature · 1 line
2.4.0
Re: [PATCH V3 2/6] PM / OPP: Rename opp init/free table routines
Quoted 11 lines · Viresh Kumar
free-table routines are opposite of init-table ones, and must be named to make that clear. Opposite of 'init' is 'exit', but those doesn't suit really well.
Replace 'init' with 'add' and 'free' with 'remove'.
Reported-by Pavel Machek <[email protected]>Reviewed-by Stephen Boyd <[email protected]>Signed-off-by Viresh Kumar <[email protected]>--- arch/arm/mach-imx/mach-imx6q.c | 2 +-
...
Quoted 1 line
drivers/cpufreq/imx6q-cpufreq.c | 6 +++---
Viresh Kumar
maintainerPATCH v3 3/6 PM / OPP: Prefix exported opp routines with dev_pm_opp_
In reply to Viresh KumarThat's the naming convention followed in most of opp core, but few routines didn't follow this, fix them.
--- arch/arm/mach-imx/mach-imx6q.c | 2 +- drivers/base/power/opp.c | 41 ++++++++++++++++++------------------ drivers/cpufreq/arm_big_little.h | 2 +- drivers/cpufreq/arm_big_little_dt.c | 4 ++-- drivers/cpufreq/cpufreq-dt.c | 10 ++++----- drivers/cpufreq/exynos5440-cpufreq.c | 6 +++--- drivers/cpufreq/imx6q-cpufreq.c | 6 +++--- drivers/cpufreq/mt8173-cpufreq.c | 6 +++--- include/linux/pm_opp.h | 24 ++++++++++----------- 9 files changed, 51 insertions(+), 50 deletions(-)
arch/arm/mach-imx/mach-imx6q.c +1 -1
@@ -350,7 +350,7 @@ static void __init imx6q_opp_init(void)return ; } -if (of_add_opp_table (cpu_dev)) { +if (dev_pm_opp_of_add_table (cpu_dev)) {pr_warn ("failed to init OPP table\n" ); goto put_node; }
drivers/base/power/opp.c +21 -20
134 lines not on this page · raw message
drivers/cpufreq/arm_big_little.h +1 -1
@@ -28,7 +28,7 @@ struct cpufreq_arm_bL_ops {/* * This must set opp table for cpu_dev in a similar way as done by -* of_add_opp_table(). +* dev_pm_opp_of_add_table(). */ int (*init_opp_table)(struct device *cpu_dev);
drivers/cpufreq/arm_big_little_dt.c +2 -2
@@ -54,7 +54,7 @@ static int dt_init_opp_table(struct device *cpu_dev)return -ENOENT ; } - ret =of_add_opp_table (cpu_dev); + ret =dev_pm_opp_of_add_table (cpu_dev);of_node_put (np);return ret;
@@ -82,7 +82,7 @@ static struct cpufreq_arm_bL_ops dt_bL_ops = { .name = "dt-bl", .get_transition_latency = dt_get_transition_latency, .init_opp_table = dt_init_opp_table, - .free_opp_table = of_remove_opp_table, + .free_opp_table = dev_pm_opp_of_remove_table, };static int generic_bL_probe (struct platform_device *pdev)
drivers/cpufreq/cpufreq-dt.c +5 -5
@@ -215,7 +215,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) }/* Get OPP-sharing information from "operating-points-v2" bindings */ - ret =of_get_cpus_sharing_opps (cpu_dev, policy->cpus); + ret =dev_pm_opp_of_get_sharing_cpus (cpu_dev, policy->cpus);if (ret) {/* * operating-points-v2 not supported, fallback to old method of
@@ -237,7 +237,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)* * OPPs might be populated at runtime, don't check for error here */ -of_cpumask_add_opp_table (policy->cpus); +dev_pm_opp_of_cpumask_add_table (policy->cpus);/* * But we need OPP table to function so if it is not there let's
@@ -260,7 +260,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)* OPP tables are initialized only for policy->cpu, do it for * others as well. */ - ret =set_cpus_sharing_opps (cpu_dev, policy->cpus); + ret =dev_pm_opp_set_sharing_cpus (cpu_dev, policy->cpus);if (ret)dev_err (cpu_dev,"%s: failed to mark OPPs as shared: %d\n" , __func__, ret);
@@ -360,7 +360,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) out_free_priv:kfree (priv); out_free_opp: -of_cpumask_remove_opp_table (policy->cpus); +dev_pm_opp_of_cpumask_remove_table (policy->cpus); out_node_put:of_node_put (np); out_put_reg_clk:
@@ -377,7 +377,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy)cpufreq_cooling_unregister (priv->cdev);dev_pm_opp_free_cpufreq_table (priv->cpu_dev, &policy->freq_table); -of_cpumask_remove_opp_table (policy->related_cpus); +dev_pm_opp_of_cpumask_remove_table (policy->related_cpus);clk_put (policy->clk);if (!IS_ERR (priv->cpu_reg))regulator_put (priv->cpu_reg);
drivers/cpufreq/exynos5440-cpufreq.c +3 -3
@@ -360,7 +360,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) goto err_put_node; } - ret =of_add_opp_table (dvfs_info->dev); + ret =dev_pm_opp_of_add_table (dvfs_info->dev);if (ret) {dev_err (dvfs_info->dev,"failed to init OPP table: %d\n" , ret); goto err_put_node;
@@ -424,7 +424,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) err_free_table:dev_pm_opp_free_cpufreq_table (dvfs_info->dev, &dvfs_info->freq_table); err_free_opp: -of_remove_opp_table (dvfs_info->dev); +dev_pm_opp_of_remove_table (dvfs_info->dev); err_put_node:of_node_put (np);dev_err (&pdev->dev,"%s: failed initialization\n" , __func__);
@@ -435,7 +435,7 @@ static int exynos_cpufreq_remove(struct platform_device *pdev) {cpufreq_unregister_driver (&exynos_driver);dev_pm_opp_free_cpufreq_table (dvfs_info->dev, &dvfs_info->freq_table); -of_remove_opp_table (dvfs_info->dev); +dev_pm_opp_of_remove_table (dvfs_info->dev);return 0 ; }
drivers/cpufreq/imx6q-cpufreq.c +3 -3
@@ -202,7 +202,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)*/ num =dev_pm_opp_get_opp_count (cpu_dev);if (num <0 ) { - ret =of_add_opp_table (cpu_dev); + ret =dev_pm_opp_of_add_table (cpu_dev);if (ret <0 ) {dev_err (cpu_dev,"failed to init OPP table: %d\n" , ret); goto put_reg;
@@ -312,7 +312,7 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)dev_pm_opp_free_cpufreq_table (cpu_dev, &freq_table); out_free_opp:if (free_opp) -of_remove_opp_table (cpu_dev); +dev_pm_opp_of_remove_table (cpu_dev); put_reg:if (!IS_ERR (arm_reg))regulator_put (arm_reg);
@@ -340,7 +340,7 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev)cpufreq_unregister_driver (&imx6q_cpufreq_driver);dev_pm_opp_free_cpufreq_table (cpu_dev, &freq_table);if (free_opp) -of_remove_opp_table (cpu_dev); +dev_pm_opp_of_remove_table (cpu_dev);regulator_put (arm_reg);if (!IS_ERR (pu_reg))regulator_put (pu_reg);
drivers/cpufreq/mt8173-cpufreq.c +3 -3
@@ -344,7 +344,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)/* Both presence and absence of sram regulator are valid cases. */ sram_reg =regulator_get_exclusive (cpu_dev,"sram" ); - ret =of_add_opp_table (cpu_dev); + ret =dev_pm_opp_of_add_table (cpu_dev);if (ret) {pr_warn ("no OPP table for cpu%d\n" , cpu); goto out_free_resources;
@@ -378,7 +378,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)return 0 ; out_free_opp_table: -of_remove_opp_table (cpu_dev); +dev_pm_opp_of_remove_table (cpu_dev); out_free_resources:if (!IS_ERR (proc_reg))
@@ -404,7 +404,7 @@ static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)if (!IS_ERR (info->inter_clk))clk_put (info->inter_clk); -of_remove_opp_table (info->cpu_dev); +dev_pm_opp_of_remove_table (info->cpu_dev); }static int mtk_cpufreq_init (struct cpufreq_policy *policy)
include/linux/pm_opp.h +12 -12
@@ -126,37 +126,37 @@ static inline struct srcu_notifier_head *dev_pm_opp_get_notifier(#endif /* CONFIG_PM_OPP */ #if defined(CONFIG_PM_OPP ) && defined(CONFIG_OF ) -int of_add_opp_table (struct device *dev); -void of_remove_opp_table (struct device *dev); -int of_cpumask_add_opp_table (cpumask_var_t cpumask); -void of_cpumask_remove_opp_table (cpumask_var_t cpumask); -int of_get_cpus_sharing_opps (struct device *cpu_dev,cpumask_var_t cpumask); -int set_cpus_sharing_opps (struct device *cpu_dev,cpumask_var_t cpumask); +int dev_pm_opp_of_add_table (struct device *dev); +void dev_pm_opp_of_remove_table (struct device *dev); +int dev_pm_opp_of_cpumask_add_table (cpumask_var_t cpumask); +void dev_pm_opp_of_cpumask_remove_table (cpumask_var_t cpumask); +int dev_pm_opp_of_get_sharing_cpus (struct device *cpu_dev,cpumask_var_t cpumask); +int dev_pm_opp_set_sharing_cpus (struct device *cpu_dev,cpumask_var_t cpumask);#else -static inline int of_add_opp_table (struct device *dev) +static inline int dev_pm_opp_of_add_table (struct device *dev) {return -EINVAL ; } -static inline void of_remove_opp_table (struct device *dev) +static inline void dev_pm_opp_of_remove_table (struct device *dev) { } -static inline int of_cpumask_add_opp_table (cpumask_var_t cpumask) +static inline int dev_pm_opp_of_cpumask_add_table (cpumask_var_t cpumask) {return -ENOSYS ; } -static inline void of_cpumask_remove_opp_table (cpumask_var_t cpumask) +static inline void dev_pm_opp_of_cpumask_remove_table (cpumask_var_t cpumask) { } -static inline int of_get_cpus_sharing_opps (struct device *cpu_dev,cpumask_var_t cpumask) +static inline int dev_pm_opp_of_get_sharing_cpus (struct device *cpu_dev,cpumask_var_t cpumask) {return -ENOSYS ; } -static inline int set_cpus_sharing_opps (struct device *cpu_dev,cpumask_var_t cpumask) +static inline int dev_pm_opp_set_sharing_cpus (struct device *cpu_dev,cpumask_var_t cpumask) {return -ENOSYS ; }
Signature · 1 line
2.4.0
Re: [PATCH V3 3/6] PM / OPP: Prefix exported opp routines with dev_pm_opp_
Quoted 7 lines · Viresh Kumar
That's the naming convention followed in most of opp core, but few routines didn't follow this, fix them.
Reviewed-by Stephen Boyd <[email protected]>Signed-off-by Viresh Kumar <[email protected]>--- arch/arm/mach-imx/mach-imx6q.c | 2 +-
...
Quoted 1 line
drivers/cpufreq/imx6q-cpufreq.c | 6 +++---
Viresh Kumar
maintainerPATCH v3 4/6 PM / OPP: Move opp core to its own directory
In reply to Viresh KumarOPP code is expanding and is already present in multiple directories (cpufreq and power). Lets move it to its own directory, to manage it better.
This also moves/renames the cpufreq_opp file to cpu.c, as it will contain helpers for cpu device. Its not just about cpufreq, other frameworks can use OPPs as well.
---
drivers/base/power/Makefile | 2 +-
drivers/base/power/opp/Makefile | 2 ++
drivers/base/power/{opp.c => opp/core.c} | 0
drivers/{cpufreq/cpufreq_opp.c => base/power/opp/cpu.c} | 4 +++-
drivers/cpufreq/Makefile | 1 -
5 files changed, 6 insertions(+), 3 deletions(-)
create mode 100644 drivers/base/power/opp/Makefile
rename drivers/base/power/{opp.c => opp/core.c} (100%)
rename drivers/{cpufreq/cpufreq_opp.c => base/power/opp/cpu.c} (97%)drivers/base/power/Makefile +1 -1
@@ -1,7 +1,7 @@ obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o -obj-$(CONFIG_PM_OPP) += opp.o +obj-$(CONFIG_PM_OPP) += opp/ obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o obj-$(CONFIG_HAVE_CLK) += clock_ops.o
drivers/base/power/opp/Makefile new file +2 -0
@@ -0,0 +1,2 @@ +ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG +obj-y += core.o cpu.o
drivers/base/power/opp/core.c renamed from drivers/base/power/opp.c +0 -0
drivers/base/power/opp/cpu.c renamed from drivers/cpufreq/cpufreq_opp.c +3 -1
@@ -1,5 +1,5 @@/* -* Generic OPP helper interface for CPUFreq drivers +* Generic OPP helper interface for CPU device * * Copyright (C) 2009-2014 Texas Instruments Incorporated. * Nishanth Menon
@@ -20,6 +20,7 @@#include <linux/rcupdate.h> #include <linux/slab.h> +#ifdef CONFIG_CPU_FREQ /** * dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device * @dev: device for which we do this operation
@@ -112,3 +113,4 @@ void dev_pm_opp_free_cpufreq_table(struct device *dev, *table = NULL; }EXPORT_SYMBOL_GPL (dev_pm_opp_free_cpufreq_table); +#endif /* CONFIG_CPU_FREQ */
drivers/cpufreq/Makefile +0 -1
@@ -1,6 +1,5 @@ # CPUfreq core obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o -obj-$(CONFIG_PM_OPP) += cpufreq_opp.o # CPUfreq stats obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
Signature · 1 line
2.4.0
Viresh Kumar
maintainerPATCH v3 5/6 PM / OPP: Move cpu specific code to opp/cpu.c
In reply to Viresh KumarMove cpu device specific code out of generic opp library, and add it to cpu.c.
Along with that, create a core-internal opp.h header, which will be used to share structures and function prototypes within opp core.
--- drivers/base/power/opp/core.c | 276 +----------------------------------------- drivers/base/power/opp/cpu.c | 160 +++++++++++++++++++++++- drivers/base/power/opp/opp.h | 143 ++++++++++++++++++++++ 3 files changed, 304 insertions(+), 275 deletions(-) create mode 100644 drivers/base/power/opp/opp.h
drivers/base/power/opp/core.c +5 -271
@@ -11,131 +11,14 @@* published by the Free Software Foundation. */ -#include <linux/cpu.h> -#include <linux/kernel.h> #include <linux/errno.h> #include <linux/err.h> #include <linux/slab.h> #include <linux/device.h> -#include <linux/list.h> -#include <linux/rculist.h> -#include <linux/rcupdate.h> -#include <linux/pm_opp.h> #include <linux/of.h> #include <linux/export.h> -/* -* Internal data structure organization with the OPP layer library is as -* follows: -* dev_opp_list (root) -* |- device 1 (represents voltage domain 1) -* | |- opp 1 (availability, freq, voltage) -* | |- opp 2 .. -* ... ... -* | `- opp n .. -* |- device 2 (represents the next voltage domain) -* ... -* `- device m (represents mth voltage domain) -* device 1, 2.. are represented by dev_opp structure while each opp -* is represented by the opp structure. -*/ - -/** -* struct dev_pm_opp - Generic OPP description structure -* @node: opp list node. The nodes are maintained throughout the lifetime -* of boot. It is expected only an optimal set of OPPs are -* added to the library by the SoC framework. -* RCU usage: opp list is traversed with RCU locks. node -* modification is possible realtime, hence the modifications -* are protected by the dev_opp_list_lock for integrity. -* IMPORTANT: the opp nodes should be maintained in increasing -* order. -* @dynamic: not-created from static DT entries. -* @available: true/false - marks if this OPP as available or not -* @turbo: true if turbo (boost) OPP -* @rate: Frequency in hertz -* @u_volt: Target voltage in microvolts corresponding to this OPP -* @u_volt_min: Minimum voltage in microvolts corresponding to this OPP -* @u_volt_max: Maximum voltage in microvolts corresponding to this OPP -* @u_amp: Maximum current drawn by the device in microamperes -* @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's -* frequency from any other OPP's frequency. -* @dev_opp: points back to the device_opp struct this opp belongs to -* @rcu_head: RCU callback head used for deferred freeing -* @np: OPP's device node. -* -* This structure stores the OPP information for a given device. -*/ -struct dev_pm_opp { -struct list_head node; - -bool available; -bool dynamic; -bool turbo; -unsigned long rate; - -unsigned long u_volt; -unsigned long u_volt_min; -unsigned long u_volt_max; -unsigned long u_amp; -unsigned long clock_latency_ns; - -struct device_opp *dev_opp; -struct rcu_head rcu_head; - -struct device_node *np; -}; - -/** -* struct device_list_opp - devices managed by 'struct device_opp' -* @node: list node -* @dev: device to which the struct object belongs -* @rcu_head: RCU callback head used for deferred freeing -* -* This is an internal data structure maintaining the list of devices that are -* managed by 'struct device_opp'. -*/ -struct device_list_opp { -struct list_head node; -const struct device *dev; -struct rcu_head rcu_head; -}; - -/** -* struct device_opp - Device opp structure -* @node: list node - contains the devices with OPPs that -* have been registered. Nodes once added are not modified in this -* list. -* RCU usage: nodes are not modified in the list of device_opp, -* however addition is possible and is secured by dev_opp_list_lock -* @srcu_head: notifier head to notify the OPP availability changes. -* @rcu_head: RCU callback head used for deferred freeing -* @dev_list: list of devices that share these OPPs -* @opp_list: list of opps -* @np: struct device_node pointer for opp's DT node. -* @shared_opp: OPP is shared between multiple devices. -* -* This is an internal data structure maintaining the link to opps attached to -* a device. This structure is not meant to be shared to users as it is -* meant for book keeping and private to OPP library. -* -* Because the opp structures can be used from both rcu and srcu readers, we -* need to wait for the grace period of both of them before freeing any -* resources. And so we have used kfree_rcu() from within call_srcu() handlers. -*/ -struct device_opp { -struct list_head node; - -struct srcu_notifier_head srcu_head; -struct rcu_head rcu_head; -struct list_head dev_list; -struct list_head opp_list; - -struct device_node *np; -unsigned long clock_latency_ns_max; -bool shared_opp; -struct dev_pm_opp *suspend_opp; -}; +#include "opp.h" /* * The root of the list of all devices. All device_opp structures branch off
@@ -200,7 +83,7 @@ static struct device_opp *_managed_opp(const struct device_node *np)* is a RCU protected pointer. This means that device_opp is valid as long * as we are under RCU lock. */ -static struct device_opp *_find_device_opp (struct device *dev) +struct device_opp *_find_device_opp (struct device *dev) {struct device_opp *dev_opp;
@@ -551,8 +434,8 @@ static void _remove_list_dev(struct device_list_opp *list_dev, _kfree_list_dev_rcu); } -static struct device_list_opp *_add_list_dev (const struct device *dev, -struct device_opp *dev_opp) +struct device_list_opp *_add_list_dev (const struct device *dev, +struct device_opp *dev_opp) {struct device_list_opp *list_dev;
@@ -1234,28 +1117,8 @@ void dev_pm_opp_of_remove_table(struct device *dev) }EXPORT_SYMBOL_GPL (dev_pm_opp_of_remove_table); -void dev_pm_opp_of_cpumask_remove_table (cpumask_var_t cpumask) -{ -struct device *cpu_dev; -int cpu; - -WARN_ON (cpumask_empty (cpumask)); - -for_each_cpu (cpu, cpumask) { - cpu_dev =get_cpu_device (cpu); -if (!cpu_dev) { -pr_err ("%s: failed to get cpu%d device\n" , __func__, - cpu); -continue ; - } - -dev_pm_opp_of_remove_table (cpu_dev); - } -} -EXPORT_SYMBOL_GPL (dev_pm_opp_of_cpumask_remove_table); -/* Returns opp descriptor node for a device, caller must do of_node_put() */ -static struct device_node *_of_get_opp_desc_node (struct device *dev) +struct device_node *_of_get_opp_desc_node (struct device *dev) {/* * TODO: Support for multiple OPP tables.
@@ -1399,133 +1262,4 @@ int dev_pm_opp_of_add_table(struct device *dev) return ret; }EXPORT_SYMBOL_GPL (dev_pm_opp_of_add_table); - -int dev_pm_opp_of_cpumask_add_table (cpumask_var_t cpumask) -{ -struct device *cpu_dev; -int cpu, ret =0 ; - -WARN_ON (cpumask_empty (cpumask)); - -for_each_cpu (cpu, cpumask) { - cpu_dev =get_cpu_device (cpu); -if (!cpu_dev) { -pr_err ("%s: failed to get cpu%d device\n" , __func__, - cpu); -continue ; - } - - ret =dev_pm_opp_of_add_table (cpu_dev); -if (ret) { -pr_err ("%s: couldn't find opp table for cpu:%d, %d\n" , - __func__, cpu, ret); - -/* Free all other OPPs */ -dev_pm_opp_of_cpumask_remove_table (cpumask); -break ; - } - } - -return ret; -} -EXPORT_SYMBOL_GPL (dev_pm_opp_of_cpumask_add_table); - -/* Required only for V1 bindings, as v2 can manage it from DT itself */ -int dev_pm_opp_set_sharing_cpus (struct device *cpu_dev,cpumask_var_t cpumask) -{ -struct device_list_opp *list_dev; -struct device_opp *dev_opp; -struct device *dev; -int cpu, ret =0 ; - -rcu_read_lock (); - - dev_opp =_find_device_opp (cpu_dev); -if (IS_ERR (dev_opp)) { - ret = -EINVAL ; - goto out_rcu_read_unlock; - } - -for_each_cpu (cpu, cpumask) { -if (cpu == cpu_dev->id) -continue ; - - dev =get_cpu_device (cpu); -if (!dev) { -dev_err (cpu_dev,"%s: failed to get cpu%d device\n" , - __func__, cpu); -continue ; - } - - list_dev =_add_list_dev (dev, dev_opp); -if (!list_dev) { -dev_err (dev,"%s: failed to add list-dev for cpu%d device\n" , - __func__, cpu); -continue ; - } - } -out_rcu_read_unlock: -rcu_read_unlock (); - -return 0 ; -} -EXPORT_SYMBOL_GPL (dev_pm_opp_set_sharing_cpus); - -/* -* Works only for OPP v2 bindings. -* -* cpumask should be already set to mask of cpu_dev->id. -* Returns -ENOENT if operating-points-v2 bindings aren't supported. -*/ -int dev_pm_opp_of_get_sharing_cpus (struct device *cpu_dev,cpumask_var_t cpumask) -{ -struct device_node *np, *tmp_np; -struct device *tcpu_dev; -int cpu, ret =0 ; - -/* Get OPP descriptor node */ - np =_of_get_opp_desc_node (cpu_dev); -if (!np) { -dev_dbg (cpu_dev,"%s: Couldn't find opp node: %ld\n" , __func__, -PTR_ERR (np)); -return -ENOENT ; - } - -/* OPPs are shared ? */ -if (!of_property_read_bool (np,"opp-shared" )) - goto put_cpu_node; - -for_each_possible_cpu (cpu) { -if (cpu == cpu_dev->id) -continue ; - - tcpu_dev =get_cpu_device (cpu); -if (!tcpu_dev) { -dev_err (cpu_dev,"%s: failed to get cpu%d device\n" , - __func__, cpu); - ret = -ENODEV ; - goto put_cpu_node; - } - -/* Get OPP descriptor node */ - tmp_np =_of_get_opp_desc_node (tcpu_dev); -if (!tmp_np) { -dev_err (tcpu_dev,"%s: Couldn't find opp node: %ld\n" , - __func__,PTR_ERR (tmp_np)); - ret =PTR_ERR (tmp_np); - goto put_cpu_node; - } - -/* CPUs are sharing opp node */ -if (np == tmp_np) -cpumask_set_cpu (cpu, cpumask); - -of_node_put (tmp_np); - } - -put_cpu_node: -of_node_put (np); -return ret; -} -EXPORT_SYMBOL_GPL (dev_pm_opp_of_get_sharing_cpus);#endif
drivers/base/power/opp/cpu.c +156 -4
176 lines not on this page · raw message
drivers/base/power/opp/opp.h new file +143 -0
143 lines not on this page · raw message
Signature · 1 line
2.4.0
Viresh Kumar
maintainerPATCH v3 6/6 PM / OPP: Add debugfs support
In reply to Viresh KumarThis patch adds debugfs support to OPP layer to export OPPs and their properties for all the devices.
This creates a top level directory: /sys/kernel/debug/opp and then device specific directories (based on device names) inside it. For
example: 'cpu0', 'cpu1', etc..
If multiple devices share the OPP table, then the real directory is created only for the first device. For all others, links are created to the real directory.
Inside the device specific directory, a separate directory is created for each OPP. And within that files per opp property.
--- drivers/base/power/opp/Makefile | 1 + drivers/base/power/opp/core.c | 15 +++ drivers/base/power/opp/debugfs.c | 217 +++++++++++++++++++++++++++++++++++++++ drivers/base/power/opp/opp.h | 43 ++++++++ 4 files changed, 276 insertions(+) create mode 100644 drivers/base/power/opp/debugfs.c
drivers/base/power/opp/Makefile +1 -0
@@ -1,2 +1,3 @@ ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG obj-y += core.o cpu.o +obj-$(CONFIG_DEBUG_FS) += debugfs.o
drivers/base/power/opp/core.c +15 -0
@@ -429,6 +429,7 @@ static void _kfree_list_dev_rcu(struct rcu_head *head)static void _remove_list_dev (struct device_list_opp *list_dev,struct device_opp *dev_opp) { +opp_debug_unregister (list_dev, dev_opp);list_del (&list_dev->node);call_srcu (&dev_opp->srcu_head.srcu, &list_dev->rcu_head, _kfree_list_dev_rcu);
@@ -438,6 +439,7 @@ struct device_list_opp *_add_list_dev(const struct device *dev, struct device_opp *dev_opp) {struct device_list_opp *list_dev; +int ret; list_dev =kzalloc (sizeof (*list_dev),GFP_KERNEL );if (!list_dev)
@@ -447,6 +449,12 @@ struct device_list_opp *_add_list_dev(const struct device *dev, list_dev->dev = dev;list_add_rcu (&list_dev->node, &dev_opp->dev_list); +/* Create debugfs entries for the dev_opp */ + ret =opp_debug_register (list_dev, dev_opp); +if (ret) +dev_err (dev,"%s: Failed to register opp debugfs (%d)\n" , + __func__, ret); +return list_dev; }
@@ -562,6 +570,7 @@ static void _opp_remove(struct device_opp *dev_opp,*/ if (notify)srcu_notifier_call_chain (&dev_opp->srcu_head,OPP_EVENT_REMOVE , opp); +opp_debug_remove_one (opp);list_del_rcu (&opp->node);call_srcu (&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
@@ -639,6 +648,7 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, {struct dev_pm_opp *opp;struct list_head *head = &dev_opp->opp_list; +int ret;/* * Insert new OPP in order of increasing frequency and discard if
@@ -669,6 +679,11 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, new_opp->dev_opp = dev_opp;list_add_rcu (&new_opp->node, head); + ret =opp_debug_create_one (new_opp, dev_opp); +if (ret) +dev_err (dev,"%s: Failed to register opp to debugfs (%d)\n" , + __func__, ret); +return 0 ; }
drivers/base/power/opp/debugfs.c new file +217 -0
217 lines not on this page · raw message
drivers/base/power/opp/opp.h +43 -0
89 lines not on this page · raw message
Signature · 1 line
2.4.0