All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Menon, Nishanth" <nm@ti.com>
To: Shawn Guo <shawn.guo@linaro.org>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>, Kevin Hilman <khilman@ti.com>,
	Richard Zhao <richard.zhao@freescale.com>,
	Russell King - ARM Linux <linux@arm.linux.org.uk>,
	Mike Turquette <mturquette@linaro.org>,
	devicetree-discuss@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org, linux-pm@vger.kernel.org,
	cpufreq@vger.kernel.org
Subject: Re: [PATCH 2/3] PM / OPP: Initialize OPP table from device tree
Date: Fri, 20 Jul 2012 01:00:26 -0500	[thread overview]
Message-ID: <CAOMWX4fq8aWpRgtBj+5FgqhMus=zJL3Ubqe9pwiz-Y3a6V3svg@mail.gmail.com> (raw)
In-Reply-To: <1342713281-31114-3-git-send-email-shawn.guo@linaro.org>

On Thu, Jul 19, 2012 at 10:54 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
> With a lot of devices booting from device tree nowadays, it requires
> that OPP table can be initialized from device tree.  The patch adds
> a helper function of_init_opp_table together with a binding doc for
> that purpose.
nice to see this happen, a quick feedback:
>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
>  Documentation/devicetree/bindings/power/opp.txt |   29 ++++++++++
>  drivers/base/power/opp.c                        |   66 +++++++++++++++++++++++
>  include/linux/opp.h                             |    4 ++
>  3 files changed, 99 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/power/opp.txt
>
> diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt
> new file mode 100644
> index 0000000..1dd0db2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/opp.txt
> @@ -0,0 +1,29 @@
> +* Generic OPP Interface
> +
> +SoCs have a standard set of tuples consisting of frequency and
> +voltage pairs that the device will support per voltage domain. These
> +are called Operating Performance Points or OPPs.
> +
> +Properties:
> +- operating-points: An array of 3-tuples items, and each item consists
> +  of frequency, voltage and enabling like <freq vol en>.
> +       freq: clock frequency in kHz
> +       vol: voltage in microvolt
> +       en: initially enabled (1) or not (0)
> +
> +Examples:
> +
> +cpu@0 {
> +       compatible = "arm,cortex-a9";
I am not sure how this works - would an example of OMAP4430, 60, 70
help? they have completely different OPP entries.

> +       reg = <0>;
> +       next-level-cache = <&L2>;
> +       operating-points = <
> +               /* kHz    uV    en */
> +               1200000 1275000 0
> +               996000  1225000 1
> +               792000  1100000 1
> +               672000  1100000 0
> +               396000  950000  1
> +               198000  850000  1

Just my 2cents, If we change en to be a flag:
0 - add, but disable
1 - add (enabled)
we could extend this further if the definition is a flag, for example:
2 - add and disable IF any of notifier chain return failure
3- add but dont call notifier chain (e.g. OPPs that are present for All SoC)

in addition, SoC might have additional properties associated with each
OPP such a flag
could be split up to mean lower 16 bits as OPP library flag and higher
16 bit to mean SoC custom flag

Example - On certain SoC a specific type of power technique is
supposed to be used per OPP, such a flag
passed on via notifiers to SoC handler might be capable of
centralizing the OPP information into the DT.

> +       >;
> +};
> diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
> index ac993ea..2d750f9 100644
> --- a/drivers/base/power/opp.c
> +++ b/drivers/base/power/opp.c
> @@ -22,6 +22,7 @@
>  #include <linux/rculist.h>
>  #include <linux/rcupdate.h>
>  #include <linux/opp.h>
> +#include <linux/of.h>
>
>  /*
>   * Internal data structure organization with the OPP layer library is as
> @@ -674,3 +675,68 @@ struct srcu_notifier_head *opp_get_notifier(struct device *dev)
>
>         return &dev_opp->head;
>  }
> +
> +#ifdef CONFIG_OF
> +/**
> + * of_init_opp_table() - Initialize opp table from device tree
> + * @dev:       device pointer used to lookup device OPPs.
> + *
> + * Register the initial OPP table with the OPP library for given device.
> + */
> +int of_init_opp_table(struct device *dev)
> +{
> +       struct device_node *np = dev->of_node;
> +       const char *propname = "operating-points";
> +       const struct property *pp;
> +       u32 *opp;
> +       int ret, i, nr;
> +
> +       pp = of_find_property(np, propname, NULL);
> +       if (!pp) {
> +               dev_err(dev, "%s: Unable to find property", __func__);
> +               return -ENODEV;
> +       }
> +
> +       opp = kzalloc(pp->length, GFP_KERNEL);
> +       if (!opp) {
> +               dev_err(dev, "%s: Unable to allocate array\n", __func__);
> +               return -ENOMEM;
> +       }
> +
> +       nr = pp->length / sizeof(u32);
error warn if the pp->length is not multiple of u32? we also expect
later on to be a multiple of 3(f,v,disable

> +       ret = of_property_read_u32_array(np, propname, opp, nr);
> +       if (ret) {
> +               dev_err(dev, "%s: Unable to read OPPs\n", __func__);
> +               goto out;
> +       }
> +
> +       nr /= 3;
> +       for (i = 0; i < nr; i++) {
> +               /*
> +                * Each OPP is a set of tuples consisting of frequency,
> +                * voltage and availability like <freq-kHz vol-uV enable>.
> +                */
> +               u32 *val = opp + i * 3;
> +
> +               val[0] *= 1000;
> +               ret = opp_add(dev, val[0], val[1]);
> +               if (ret) {
> +                       dev_warn(dev, "%s: Failed to add OPP %d: %d\n",
> +                                __func__, val[0], ret);
> +                       continue;
> +               }
> +
> +               if (!val[2]) {
> +                       ret = opp_disable(dev, val[0]);
Since we are updating the table out of context of the SoC users,
consider what might happen if someone where to operate on the OPP
after opp_add, but before opp_disable?
instead of having the pain of adding an OPP and then disabling it,
since the code will now move to core OPP
library itself, wont it be better to hold dev_opp_list_lock and update
the full table with a proper list walk - yes
the current opp_add and opp_disable apis would need refactoring to be
reusable. It will also save on
synchronize_rcu calls on multiple iterations of the list.


> +                       if (ret)
> +                               dev_warn(dev, "%s: Failed to disable OPP %d: %d\n",
> +                                        __func__, val[0], ret);

umm... but we override the return with 0? OPP add failure might
indicate the table is invalid/corrupted - or no memory.
What is the point in populating a bad table up? having a singular
function with direct access to internal structures
might save us these un-necessary dilemma.


> +               }
> +       }
> +
> +       ret = 0;
> +out:
> +       kfree(opp);
> +       return ret;
> +}
> +#endif
> diff --git a/include/linux/opp.h b/include/linux/opp.h
> index 2a4e5fa..fd165ad 100644
> --- a/include/linux/opp.h
> +++ b/include/linux/opp.h
> @@ -48,6 +48,10 @@ int opp_disable(struct device *dev, unsigned long freq);
>
>  struct srcu_notifier_head *opp_get_notifier(struct device *dev);
>
> +#ifdef CONFIG_OF
> +int of_init_opp_table(struct device *dev);

#else
static inline int of_init_opp_table(struct device *dev) { return -EINVAL; }
?

> +#endif
> +
>  #else
>  static inline unsigned long opp_get_voltage(struct opp *opp)
>  {


Regards,
Nishanth Menon

WARNING: multiple messages have this Message-ID (diff)
From: nm@ti.com (Menon, Nishanth)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 2/3] PM / OPP: Initialize OPP table from device tree
Date: Fri, 20 Jul 2012 01:00:26 -0500	[thread overview]
Message-ID: <CAOMWX4fq8aWpRgtBj+5FgqhMus=zJL3Ubqe9pwiz-Y3a6V3svg@mail.gmail.com> (raw)
In-Reply-To: <1342713281-31114-3-git-send-email-shawn.guo@linaro.org>

On Thu, Jul 19, 2012 at 10:54 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
> With a lot of devices booting from device tree nowadays, it requires
> that OPP table can be initialized from device tree.  The patch adds
> a helper function of_init_opp_table together with a binding doc for
> that purpose.
nice to see this happen, a quick feedback:
>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> ---
>  Documentation/devicetree/bindings/power/opp.txt |   29 ++++++++++
>  drivers/base/power/opp.c                        |   66 +++++++++++++++++++++++
>  include/linux/opp.h                             |    4 ++
>  3 files changed, 99 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/power/opp.txt
>
> diff --git a/Documentation/devicetree/bindings/power/opp.txt b/Documentation/devicetree/bindings/power/opp.txt
> new file mode 100644
> index 0000000..1dd0db2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/opp.txt
> @@ -0,0 +1,29 @@
> +* Generic OPP Interface
> +
> +SoCs have a standard set of tuples consisting of frequency and
> +voltage pairs that the device will support per voltage domain. These
> +are called Operating Performance Points or OPPs.
> +
> +Properties:
> +- operating-points: An array of 3-tuples items, and each item consists
> +  of frequency, voltage and enabling like <freq vol en>.
> +       freq: clock frequency in kHz
> +       vol: voltage in microvolt
> +       en: initially enabled (1) or not (0)
> +
> +Examples:
> +
> +cpu at 0 {
> +       compatible = "arm,cortex-a9";
I am not sure how this works - would an example of OMAP4430, 60, 70
help? they have completely different OPP entries.

> +       reg = <0>;
> +       next-level-cache = <&L2>;
> +       operating-points = <
> +               /* kHz    uV    en */
> +               1200000 1275000 0
> +               996000  1225000 1
> +               792000  1100000 1
> +               672000  1100000 0
> +               396000  950000  1
> +               198000  850000  1

Just my 2cents, If we change en to be a flag:
0 - add, but disable
1 - add (enabled)
we could extend this further if the definition is a flag, for example:
2 - add and disable IF any of notifier chain return failure
3- add but dont call notifier chain (e.g. OPPs that are present for All SoC)

in addition, SoC might have additional properties associated with each
OPP such a flag
could be split up to mean lower 16 bits as OPP library flag and higher
16 bit to mean SoC custom flag

Example - On certain SoC a specific type of power technique is
supposed to be used per OPP, such a flag
passed on via notifiers to SoC handler might be capable of
centralizing the OPP information into the DT.

> +       >;
> +};
> diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
> index ac993ea..2d750f9 100644
> --- a/drivers/base/power/opp.c
> +++ b/drivers/base/power/opp.c
> @@ -22,6 +22,7 @@
>  #include <linux/rculist.h>
>  #include <linux/rcupdate.h>
>  #include <linux/opp.h>
> +#include <linux/of.h>
>
>  /*
>   * Internal data structure organization with the OPP layer library is as
> @@ -674,3 +675,68 @@ struct srcu_notifier_head *opp_get_notifier(struct device *dev)
>
>         return &dev_opp->head;
>  }
> +
> +#ifdef CONFIG_OF
> +/**
> + * of_init_opp_table() - Initialize opp table from device tree
> + * @dev:       device pointer used to lookup device OPPs.
> + *
> + * Register the initial OPP table with the OPP library for given device.
> + */
> +int of_init_opp_table(struct device *dev)
> +{
> +       struct device_node *np = dev->of_node;
> +       const char *propname = "operating-points";
> +       const struct property *pp;
> +       u32 *opp;
> +       int ret, i, nr;
> +
> +       pp = of_find_property(np, propname, NULL);
> +       if (!pp) {
> +               dev_err(dev, "%s: Unable to find property", __func__);
> +               return -ENODEV;
> +       }
> +
> +       opp = kzalloc(pp->length, GFP_KERNEL);
> +       if (!opp) {
> +               dev_err(dev, "%s: Unable to allocate array\n", __func__);
> +               return -ENOMEM;
> +       }
> +
> +       nr = pp->length / sizeof(u32);
error warn if the pp->length is not multiple of u32? we also expect
later on to be a multiple of 3(f,v,disable

> +       ret = of_property_read_u32_array(np, propname, opp, nr);
> +       if (ret) {
> +               dev_err(dev, "%s: Unable to read OPPs\n", __func__);
> +               goto out;
> +       }
> +
> +       nr /= 3;
> +       for (i = 0; i < nr; i++) {
> +               /*
> +                * Each OPP is a set of tuples consisting of frequency,
> +                * voltage and availability like <freq-kHz vol-uV enable>.
> +                */
> +               u32 *val = opp + i * 3;
> +
> +               val[0] *= 1000;
> +               ret = opp_add(dev, val[0], val[1]);
> +               if (ret) {
> +                       dev_warn(dev, "%s: Failed to add OPP %d: %d\n",
> +                                __func__, val[0], ret);
> +                       continue;
> +               }
> +
> +               if (!val[2]) {
> +                       ret = opp_disable(dev, val[0]);
Since we are updating the table out of context of the SoC users,
consider what might happen if someone where to operate on the OPP
after opp_add, but before opp_disable?
instead of having the pain of adding an OPP and then disabling it,
since the code will now move to core OPP
library itself, wont it be better to hold dev_opp_list_lock and update
the full table with a proper list walk - yes
the current opp_add and opp_disable apis would need refactoring to be
reusable. It will also save on
synchronize_rcu calls on multiple iterations of the list.


> +                       if (ret)
> +                               dev_warn(dev, "%s: Failed to disable OPP %d: %d\n",
> +                                        __func__, val[0], ret);

umm... but we override the return with 0? OPP add failure might
indicate the table is invalid/corrupted - or no memory.
What is the point in populating a bad table up? having a singular
function with direct access to internal structures
might save us these un-necessary dilemma.


> +               }
> +       }
> +
> +       ret = 0;
> +out:
> +       kfree(opp);
> +       return ret;
> +}
> +#endif
> diff --git a/include/linux/opp.h b/include/linux/opp.h
> index 2a4e5fa..fd165ad 100644
> --- a/include/linux/opp.h
> +++ b/include/linux/opp.h
> @@ -48,6 +48,10 @@ int opp_disable(struct device *dev, unsigned long freq);
>
>  struct srcu_notifier_head *opp_get_notifier(struct device *dev);
>
> +#ifdef CONFIG_OF
> +int of_init_opp_table(struct device *dev);

#else
static inline int of_init_opp_table(struct device *dev) { return -EINVAL; }
?

> +#endif
> +
>  #else
>  static inline unsigned long opp_get_voltage(struct opp *opp)
>  {


Regards,
Nishanth Menon

  reply	other threads:[~2012-07-20  6:00 UTC|newest]

Thread overview: 68+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-07-19 15:54 [PATCH 0/3] Add a generic cpufreq-cpu0 driver Shawn Guo
2012-07-19 15:54 ` Shawn Guo
2012-07-19 15:54 ` [PATCH 1/3] ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp Shawn Guo
2012-07-19 15:54   ` Shawn Guo
2012-07-20  6:36   ` Shilimkar, Santosh
2012-07-20  6:36     ` Shilimkar, Santosh
2012-07-20  7:56     ` Shawn Guo
2012-07-20  7:56       ` Shawn Guo
2012-07-20  8:27       ` Shilimkar, Santosh
2012-07-20  8:27         ` Shilimkar, Santosh
2012-07-19 15:54 ` [PATCH 2/3] PM / OPP: Initialize OPP table from device tree Shawn Guo
2012-07-19 15:54   ` Shawn Guo
2012-07-20  6:00   ` Menon, Nishanth [this message]
2012-07-20  6:00     ` Menon, Nishanth
2012-07-20  8:46     ` Shawn Guo
2012-07-20  8:46       ` Shawn Guo
2012-07-20  9:04       ` Menon, Nishanth
2012-07-20  9:04         ` Menon, Nishanth
2012-07-19 15:54 ` [PATCH 3/3] cpufreq: Add a generic cpufreq-cpu0 driver Shawn Guo
2012-07-19 15:54   ` Shawn Guo
2012-07-20  6:52   ` Shilimkar, Santosh
2012-07-20  6:52     ` Shilimkar, Santosh
     [not found]     ` <CAMQu2gw32LogXJJa+K5ZjmCZzBNK3FY2wYwZXU8fsftsVzEO2Q-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-07-20 12:33       ` Shawn Guo
2012-07-20 12:33         ` Shawn Guo
2012-07-20 15:50         ` Turquette, Mike
2012-07-20 15:50           ` Turquette, Mike
2012-07-21  5:04           ` Shilimkar, Santosh
2012-07-21  5:04             ` Shilimkar, Santosh
2012-07-21  6:38             ` Shawn Guo
2012-07-21  6:38               ` Shawn Guo
2012-07-27  2:04               ` Richard Zhao
2012-07-27  2:04                 ` Richard Zhao
2012-07-30  4:57                 ` Shawn Guo
2012-07-30  4:57                   ` Shawn Guo
2012-07-20 12:51   ` Richard Zhao
2012-07-20 12:51     ` Richard Zhao
2012-07-20 13:15     ` Shawn Guo
2012-07-20 13:15       ` Shawn Guo
     [not found]   ` <1342713281-31114-4-git-send-email-shawn.guo-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2012-07-26 13:11     ` Mark Brown
2012-07-26 13:11       ` Mark Brown
     [not found]       ` <20120726131121.GB7306-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2012-07-27  2:13         ` Richard Zhao
2012-07-27  2:13           ` Richard Zhao
2012-07-27 10:08           ` Mark Brown
2012-07-27 10:08             ` Mark Brown
2012-07-30  6:52       ` Shawn Guo
2012-07-30  6:52         ` Shawn Guo
2012-07-30  8:20         ` Shawn Guo
2012-07-30  8:20           ` Shawn Guo
2012-07-30 18:55           ` Mark Brown
2012-07-30 18:55             ` Mark Brown
2012-07-30 18:53         ` Mark Brown
2012-07-30 18:53           ` Mark Brown
2012-07-31  4:20           ` Shawn Guo
2012-07-31  4:20             ` Shawn Guo
2012-07-31 13:40             ` Mark Brown
2012-07-31 13:40               ` Mark Brown
2012-07-27  6:33   ` Richard Zhao
2012-07-27  6:33     ` Richard Zhao
2012-07-30  8:17     ` Shawn Guo
2012-07-30  8:17       ` Shawn Guo
2012-07-30  8:50       ` Richard Zhao
2012-07-30  8:50         ` Richard Zhao
2012-07-30  9:24         ` Shawn Guo
2012-07-30  9:24           ` Shawn Guo
2012-07-19 18:39 ` [PATCH 0/3] " Rafael J. Wysocki
2012-07-19 18:39   ` Rafael J. Wysocki
2012-07-20  0:29   ` Shawn Guo
2012-07-20  0:29     ` Shawn Guo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAOMWX4fq8aWpRgtBj+5FgqhMus=zJL3Ubqe9pwiz-Y3a6V3svg@mail.gmail.com' \
    --to=nm@ti.com \
    --cc=cpufreq@vger.kernel.org \
    --cc=devicetree-discuss@lists.ozlabs.org \
    --cc=khilman@ti.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux@arm.linux.org.uk \
    --cc=mturquette@linaro.org \
    --cc=richard.zhao@freescale.com \
    --cc=rjw@sisk.pl \
    --cc=shawn.guo@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.