Re: [PATCH] arm: omap: Use only valid power domain states

2012-05-03 Thread Jean Pihet
Hi Mark,

On Thu, May 3, 2012 at 12:04 AM, Mark A. Greer  wrote:
> On Tue, May 01, 2012 at 10:47:35AM +0200, Jean Pihet wrote:
>> Hi Mark,
>
> Hi Jean.  Thanks for the review.
>
>> On Mon, Apr 30, 2012 at 11:25 PM, Mark A. Greer  
>> wrote:
>> > From: "Mark A. Greer" 
>
>> > diff --git a/arch/arm/mach-omap2/cpuidle34xx.c 
>> > b/arch/arm/mach-omap2/cpuidle34xx.c
>> > index 5358664..2c91711 100644
>> > --- a/arch/arm/mach-omap2/cpuidle34xx.c
>> > +++ b/arch/arm/mach-omap2/cpuidle34xx.c
>> > @@ -175,19 +175,25 @@ static int next_valid_state(struct cpuidle_device 
>> > *dev,
>> >        struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
>> >        struct cpuidle_state *curr = &drv->states[index];
>> >        struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
>> > -       u32 mpu_deepest_state = PWRDM_POWER_RET;
>> > -       u32 core_deepest_state = PWRDM_POWER_RET;
>> > +       u32 mpu_deepest_state, mpu_deepest_possible;
>> > +       u32 core_deepest_state, core_deepest_possible;
>> >        int next_index = -1;
>> >
>> > +       mpu_deepest_possible = pwrdm_get_deepest_state(mpu_pd);
>> > +       mpu_deepest_state = max_t(u32, mpu_deepest_possible, 
>> > PWRDM_POWER_RET);
>> I do not think you need to change the pwrdm API and the cpuidle code for 
>> that.
>> Instead you should use the pwrst* fields in the power domains data
>> files, which allow to specify the allowed states.
>> After reading the rest of your patches it seems you are addressing the
>> issue in a subsequent patch 'arm: omap3: am35x: Set proper powerdomain
>> states'.
>
> That patch sets the allowable power domain states for the am35x; the intent
> of this patch was to make the code respect what is set in the pwrst* fields.
>
>> > diff --git a/arch/arm/mach-omap2/powerdomain.c 
>> > b/arch/arm/mach-omap2/powerdomain.c
>> > index 96ad3dbe..9c80c19 100644
>> > --- a/arch/arm/mach-omap2/powerdomain.c
>> > +++ b/arch/arm/mach-omap2/powerdomain.c
>> > @@ -1078,3 +1078,28 @@ bool pwrdm_can_ever_lose_context(struct powerdomain 
>> > *pwrdm)
>> >
>> >        return 0;
>> >  }
>> > +
>> > +/**
>> > + * pwrdm_get_deepest_state - Get deepest valid state domain can enter
>> > + * @pwrdm: struct powerdomain *
>> > + *
>> > + * Find and return the deepest valid state a power domain can be in.
>> > + * Returns the deepest state that @pwrdm can enter.
>> > + */
>> > +u32 pwrdm_get_deepest_state(struct powerdomain *pwrdm)
>> > +{
>> > +       u32 valid_states, deepest_state;
>> > +
>> > +       valid_states = pwrdm->pwrsts;
>> > +
>> > +       if (valid_states & PWRSTS_OFF)
>> > +               deepest_state = PWRDM_POWER_OFF;
>> > +       else if (valid_states & PWRSTS_RET)
>> > +               deepest_state = PWRDM_POWER_RET;
>> > +       else if (valid_states & PWRSTS_INACTIVE)
>> > +               deepest_state = PWRDM_POWER_INACTIVE;
>> > +       else
>> > +               deepest_state = PWRDM_POWER_ON;
>> > +
>> > +       return deepest_state;
>> > +}
>>
>> The pwrdm API already performs those checks on pwrst*, cf.
>> pwrdm_set_next_pwrst for example.
>
> Well, sort of.  pwrdm_set_next_pwrst() fails if its an invalid state
> returning -EINVAL.  Very few of the callers actually check to see if
> it failed so they don't try the "next-one-up" power state.  The net
> result is that the next state doesn't change even though it could
> move to a lower state (just not the one that was asked for).
>
> Is that acceptable?
No that is not acceptable. In fact the next power state should only be
set using omap_set_pwrdm_state, which falls back to the next valid
power state. Note: my latest patches about the functional power states
is using omap_set_pwrdm_state as the only function to set the power,
logic states.

> Another sort of strange one is omap3_pm_off_mode_enable().  If its
> called with 'enable' set and PWRDM_POWER_OFF isn't a valid state,
> omap_set_pwrdm_state() will return 0 and leave the next state alone.
> When omap3_pm_off_mode_enable() is called again with 'enable' set,
> omap_set_pwrdm_state() will find the lowest valid state >= RET.
> So, if you had a device where OFF wasn't valid but RET was and
> its currently ON, when the user enables OFF mode, it stays ON
> and when they disable OFF mode, it moves to RET.
>
> Is that acceptable?
No. omap_set_pwrdm_state should be fixed in that case.
In fact the enable_off_mode flag is scheduled for removal in favor of
the PM QoS constraints.

> If the things above are acceptable, then I think you're right, we can
> forget this patch.  FYI, the am35x appears to work okay and no invalid
> states are entered (according to /sys/kernel/debug/pm_debug/count)
> without this patch.
I think we should fix the existing code if it has problems, not add
more specific code.

Kevin, what is your take on this?

> Mark

Regards,
Jean
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vge

Re: [PATCH] arm: omap: Use only valid power domain states

2012-05-02 Thread Mark A. Greer
On Tue, May 01, 2012 at 10:47:35AM +0200, Jean Pihet wrote:
> Hi Mark,

Hi Jean.  Thanks for the review.

> On Mon, Apr 30, 2012 at 11:25 PM, Mark A. Greer  
> wrote:
> > From: "Mark A. Greer" 

> > diff --git a/arch/arm/mach-omap2/cpuidle34xx.c 
> > b/arch/arm/mach-omap2/cpuidle34xx.c
> > index 5358664..2c91711 100644
> > --- a/arch/arm/mach-omap2/cpuidle34xx.c
> > +++ b/arch/arm/mach-omap2/cpuidle34xx.c
> > @@ -175,19 +175,25 @@ static int next_valid_state(struct cpuidle_device 
> > *dev,
> >        struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
> >        struct cpuidle_state *curr = &drv->states[index];
> >        struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
> > -       u32 mpu_deepest_state = PWRDM_POWER_RET;
> > -       u32 core_deepest_state = PWRDM_POWER_RET;
> > +       u32 mpu_deepest_state, mpu_deepest_possible;
> > +       u32 core_deepest_state, core_deepest_possible;
> >        int next_index = -1;
> >
> > +       mpu_deepest_possible = pwrdm_get_deepest_state(mpu_pd);
> > +       mpu_deepest_state = max_t(u32, mpu_deepest_possible, 
> > PWRDM_POWER_RET);
> I do not think you need to change the pwrdm API and the cpuidle code for that.
> Instead you should use the pwrst* fields in the power domains data
> files, which allow to specify the allowed states.
> After reading the rest of your patches it seems you are addressing the
> issue in a subsequent patch 'arm: omap3: am35x: Set proper powerdomain
> states'.

That patch sets the allowable power domain states for the am35x; the intent
of this patch was to make the code respect what is set in the pwrst* fields.

> > diff --git a/arch/arm/mach-omap2/powerdomain.c 
> > b/arch/arm/mach-omap2/powerdomain.c
> > index 96ad3dbe..9c80c19 100644
> > --- a/arch/arm/mach-omap2/powerdomain.c
> > +++ b/arch/arm/mach-omap2/powerdomain.c
> > @@ -1078,3 +1078,28 @@ bool pwrdm_can_ever_lose_context(struct powerdomain 
> > *pwrdm)
> >
> >        return 0;
> >  }
> > +
> > +/**
> > + * pwrdm_get_deepest_state - Get deepest valid state domain can enter
> > + * @pwrdm: struct powerdomain *
> > + *
> > + * Find and return the deepest valid state a power domain can be in.
> > + * Returns the deepest state that @pwrdm can enter.
> > + */
> > +u32 pwrdm_get_deepest_state(struct powerdomain *pwrdm)
> > +{
> > +       u32 valid_states, deepest_state;
> > +
> > +       valid_states = pwrdm->pwrsts;
> > +
> > +       if (valid_states & PWRSTS_OFF)
> > +               deepest_state = PWRDM_POWER_OFF;
> > +       else if (valid_states & PWRSTS_RET)
> > +               deepest_state = PWRDM_POWER_RET;
> > +       else if (valid_states & PWRSTS_INACTIVE)
> > +               deepest_state = PWRDM_POWER_INACTIVE;
> > +       else
> > +               deepest_state = PWRDM_POWER_ON;
> > +
> > +       return deepest_state;
> > +}
> 
> The pwrdm API already performs those checks on pwrst*, cf.
> pwrdm_set_next_pwrst for example.

Well, sort of.  pwrdm_set_next_pwrst() fails if its an invalid state
returning -EINVAL.  Very few of the callers actually check to see if
it failed so they don't try the "next-one-up" power state.  The net
result is that the next state doesn't change even though it could
move to a lower state (just not the one that was asked for).

Is that acceptable?

Another sort of strange one is omap3_pm_off_mode_enable().  If its
called with 'enable' set and PWRDM_POWER_OFF isn't a valid state,
omap_set_pwrdm_state() will return 0 and leave the next state alone.
When omap3_pm_off_mode_enable() is called again with 'enable' set,
omap_set_pwrdm_state() will find the lowest valid state >= RET.
So, if you had a device where OFF wasn't valid but RET was and
its currently ON, when the user enables OFF mode, it stays ON
and when they disable OFF mode, it moves to RET.

Is that acceptable?

If the things above are acceptable, then I think you're right, we can
forget this patch.  FYI, the am35x appears to work okay and no invalid
states are entered (according to /sys/kernel/debug/pm_debug/count)
without this patch.

Mark
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] arm: omap: Use only valid power domain states

2012-05-01 Thread Jean Pihet
Hi Mark,

On Mon, Apr 30, 2012 at 11:25 PM, Mark A. Greer  wrote:
> From: "Mark A. Greer" 
>
> Some parts of the OMAP code assume that all power
> domains support certain states (e.g., RET & OFF).
> This isn't always true (e.g., the am35x family of
> SoC's) so those assumptions need to be removed.
>
> Remove those assumptions by looking up the deepest
> state that a power domain can be in whereever its
> being blindly set.  The 'max()' of the deepest
> state and what the code formerly wanted to set it
> to, is the correct state.  If the code formerly
> wanted to set it to PWRDM_POWER_OFF, then the
> deepest possible state will be used (i.e., no
> need to perform the 'max()').
>
> The code still assumes that ON is a valid state.
>
> Signed-off-by: Mark A. Greer 
> ---
>
> These patches apply on top of Kevin's patch series,
>      "[PATCH/RFT 0/8] ARM: OMAP: remove IP checks from SoC family detection"
>
> Tested on an am3517 evm and am37x evm.
>
>  arch/arm/mach-omap2/cpuidle34xx.c |   19 +--
>  arch/arm/mach-omap2/pm34xx.c      |   15 +--
>  arch/arm/mach-omap2/powerdomain.c |   25 +
>  arch/arm/mach-omap2/powerdomain.h |    2 ++
>  4 files changed, 49 insertions(+), 12 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/cpuidle34xx.c 
> b/arch/arm/mach-omap2/cpuidle34xx.c
> index 5358664..2c91711 100644
> --- a/arch/arm/mach-omap2/cpuidle34xx.c
> +++ b/arch/arm/mach-omap2/cpuidle34xx.c
> @@ -175,19 +175,25 @@ static int next_valid_state(struct cpuidle_device *dev,
>        struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
>        struct cpuidle_state *curr = &drv->states[index];
>        struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
> -       u32 mpu_deepest_state = PWRDM_POWER_RET;
> -       u32 core_deepest_state = PWRDM_POWER_RET;
> +       u32 mpu_deepest_state, mpu_deepest_possible;
> +       u32 core_deepest_state, core_deepest_possible;
>        int next_index = -1;
>
> +       mpu_deepest_possible = pwrdm_get_deepest_state(mpu_pd);
> +       mpu_deepest_state = max_t(u32, mpu_deepest_possible, PWRDM_POWER_RET);
I do not think you need to change the pwrdm API and the cpuidle code for that.

Instead you should use the pwrst* fields in the power domains data
files, which allow to specify the allowed states.
After reading the rest of your patches it seems you are addressing the
issue in a subsequent patch 'arm: omap3: am35x: Set proper powerdomain
states'.

> +
> +       core_deepest_possible = pwrdm_get_deepest_state(core_pd);
> +       core_deepest_state = max_t(u32, core_deepest_possible, 
> PWRDM_POWER_RET);
> +
>        if (enable_off_mode) {
> -               mpu_deepest_state = PWRDM_POWER_OFF;
> +               mpu_deepest_state = mpu_deepest_possible;
>                /*
>                 * Erratum i583: valable for ES rev < Es1.2 on 3630.
>                 * CORE OFF mode is not supported in a stable form, restrict
>                 * instead the CORE state to RET.
>                 */
>                if (!IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583))
> -                       core_deepest_state = PWRDM_POWER_OFF;
> +                       core_deepest_state = core_deepest_possible;
>        }
>
>        /* Check if current state is valid */
> @@ -422,8 +428,9 @@ int __init omap3_idle_init(void)
>                pr_warn("%s: core off state C7 disabled due to i583\n",
>                        __func__);
>        }
> -       cx->mpu_state = PWRDM_POWER_OFF;
> -       cx->core_state = PWRDM_POWER_OFF;
> +
> +       cx->mpu_state = pwrdm_get_deepest_state(mpu_pd);
> +       cx->core_state = pwrdm_get_deepest_state(core_pd);
>
>        drv->state_count = OMAP3_NUM_STATES;
>        cpuidle_register_driver(&omap3_idle_driver);
> diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
> index ec92676..40d8d07 100644
> --- a/arch/arm/mach-omap2/pm34xx.c
> +++ b/arch/arm/mach-omap2/pm34xx.c
> @@ -614,12 +614,11 @@ void omap3_pm_off_mode_enable(int enable)
>        struct power_state *pwrst;
>        u32 state;
>
> -       if (enable)
> -               state = PWRDM_POWER_OFF;
> -       else
> -               state = PWRDM_POWER_RET;
> -
>        list_for_each_entry(pwrst, &pwrst_list, node) {
> +               state = pwrdm_get_deepest_state(pwrst->pwrdm);
> +               if (!enable)
> +                       state = max_t(u32, state, PWRDM_POWER_RET);
> +
>                if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583) &&
>                                pwrst->pwrdm == core_pwrdm &&
>                                state == PWRDM_POWER_OFF) {
> @@ -660,6 +659,7 @@ int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, 
> int state)
>  static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
>  {
>        struct power_state *pwrst;
> +       u32 state;
>
>        if (!pwrdm->pwrsts)
>                return 0;
> @@ -668,7 +668,10 @@ static int __init pwrdms_setup(struc

[PATCH] arm: omap: Use only valid power domain states

2012-04-30 Thread Mark A. Greer
From: "Mark A. Greer" 

Some parts of the OMAP code assume that all power
domains support certain states (e.g., RET & OFF).
This isn't always true (e.g., the am35x family of
SoC's) so those assumptions need to be removed.

Remove those assumptions by looking up the deepest
state that a power domain can be in whereever its
being blindly set.  The 'max()' of the deepest
state and what the code formerly wanted to set it
to, is the correct state.  If the code formerly
wanted to set it to PWRDM_POWER_OFF, then the
deepest possible state will be used (i.e., no
need to perform the 'max()').

The code still assumes that ON is a valid state.

Signed-off-by: Mark A. Greer 
---

These patches apply on top of Kevin's patch series,
  "[PATCH/RFT 0/8] ARM: OMAP: remove IP checks from SoC family detection"

Tested on an am3517 evm and am37x evm.

 arch/arm/mach-omap2/cpuidle34xx.c |   19 +--
 arch/arm/mach-omap2/pm34xx.c  |   15 +--
 arch/arm/mach-omap2/powerdomain.c |   25 +
 arch/arm/mach-omap2/powerdomain.h |2 ++
 4 files changed, 49 insertions(+), 12 deletions(-)

diff --git a/arch/arm/mach-omap2/cpuidle34xx.c 
b/arch/arm/mach-omap2/cpuidle34xx.c
index 5358664..2c91711 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -175,19 +175,25 @@ static int next_valid_state(struct cpuidle_device *dev,
struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
struct cpuidle_state *curr = &drv->states[index];
struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
-   u32 mpu_deepest_state = PWRDM_POWER_RET;
-   u32 core_deepest_state = PWRDM_POWER_RET;
+   u32 mpu_deepest_state, mpu_deepest_possible;
+   u32 core_deepest_state, core_deepest_possible;
int next_index = -1;
 
+   mpu_deepest_possible = pwrdm_get_deepest_state(mpu_pd);
+   mpu_deepest_state = max_t(u32, mpu_deepest_possible, PWRDM_POWER_RET);
+
+   core_deepest_possible = pwrdm_get_deepest_state(core_pd);
+   core_deepest_state = max_t(u32, core_deepest_possible, PWRDM_POWER_RET);
+
if (enable_off_mode) {
-   mpu_deepest_state = PWRDM_POWER_OFF;
+   mpu_deepest_state = mpu_deepest_possible;
/*
 * Erratum i583: valable for ES rev < Es1.2 on 3630.
 * CORE OFF mode is not supported in a stable form, restrict
 * instead the CORE state to RET.
 */
if (!IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583))
-   core_deepest_state = PWRDM_POWER_OFF;
+   core_deepest_state = core_deepest_possible;
}
 
/* Check if current state is valid */
@@ -422,8 +428,9 @@ int __init omap3_idle_init(void)
pr_warn("%s: core off state C7 disabled due to i583\n",
__func__);
}
-   cx->mpu_state = PWRDM_POWER_OFF;
-   cx->core_state = PWRDM_POWER_OFF;
+
+   cx->mpu_state = pwrdm_get_deepest_state(mpu_pd);
+   cx->core_state = pwrdm_get_deepest_state(core_pd);
 
drv->state_count = OMAP3_NUM_STATES;
cpuidle_register_driver(&omap3_idle_driver);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index ec92676..40d8d07 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -614,12 +614,11 @@ void omap3_pm_off_mode_enable(int enable)
struct power_state *pwrst;
u32 state;
 
-   if (enable)
-   state = PWRDM_POWER_OFF;
-   else
-   state = PWRDM_POWER_RET;
-
list_for_each_entry(pwrst, &pwrst_list, node) {
+   state = pwrdm_get_deepest_state(pwrst->pwrdm);
+   if (!enable)
+   state = max_t(u32, state, PWRDM_POWER_RET);
+
if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583) &&
pwrst->pwrdm == core_pwrdm &&
state == PWRDM_POWER_OFF) {
@@ -660,6 +659,7 @@ int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, 
int state)
 static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
 {
struct power_state *pwrst;
+   u32 state;
 
if (!pwrdm->pwrsts)
return 0;
@@ -668,7 +668,10 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, 
void *unused)
if (!pwrst)
return -ENOMEM;
pwrst->pwrdm = pwrdm;
-   pwrst->next_state = PWRDM_POWER_RET;
+
+   state = pwrdm_get_deepest_state(pwrdm);
+   pwrst->next_state = max_t(u32, state, PWRDM_POWER_RET);
+
list_add(&pwrst->node, &pwrst_list);
 
if (pwrdm_has_hdwr_sar(pwrdm))
diff --git a/arch/arm/mach-omap2/powerdomain.c 
b/arch/arm/mach-omap2/powerdomain.c
index 96ad3dbe..9c80c19 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -1078,3 +1078,28 @@ bool pwr