2020-04-22 05:17:25

by Chunyan Zhang

[permalink] [raw]
Subject: [PATCH] PM: sleep: call devfreq_suspend/resume and cpufreq_suspend/resume in pairs.

From: Vincent Wang <[email protected]>

If dpm_prepare() fails in dpm_suspend_start(), dpm_suspend() can't be
called. And then, devfreq_suspend() and cpufreq_suspend() will not be
called in the suspend flow.

But in the resiume flow, devfreq_resume() and cpufreq_resume() will
be called.

This patch will ensure that devfreq_suspend/devfreq_resume and
cpufreq_suspend/cpufreq_resume are called in pairs.

Signed-off-by: Vincent Wang <[email protected]>
Signed-off-by: Samer Xie <[email protected]>
Signed-off-by: Chunyan Zhang <[email protected]>
---
drivers/base/power/main.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index fdd508a78ffd..eb3d987d43e0 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1866,9 +1866,6 @@ int dpm_suspend(pm_message_t state)
trace_suspend_resume(TPS("dpm_suspend"), state.event, true);
might_sleep();

- devfreq_suspend();
- cpufreq_suspend();
-
mutex_lock(&dpm_list_mtx);
pm_transition = state;
async_error = 0;
@@ -1988,6 +1985,9 @@ int dpm_prepare(pm_message_t state)
trace_suspend_resume(TPS("dpm_prepare"), state.event, true);
might_sleep();

+ devfreq_suspend();
+ cpufreq_suspend();
+
/*
* Give a chance for the known devices to complete their probes, before
* disable probing of devices. This sync point is important at least
--
2.20.1


2020-04-22 09:07:09

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH] PM: sleep: call devfreq_suspend/resume and cpufreq_suspend/resume in pairs.

On Wed, Apr 22, 2020 at 7:15 AM Chunyan Zhang <[email protected]> wrote:
>
> From: Vincent Wang <[email protected]>
>
> If dpm_prepare() fails in dpm_suspend_start(), dpm_suspend() can't be
> called.

That's correct.

> And then, devfreq_suspend() and cpufreq_suspend() will not be
> called in the suspend flow.

Right.

> But in the resiume flow, devfreq_resume() and cpufreq_resume() will
> be called.

Right, and they are expected to cope with the situation.

> This patch will ensure that devfreq_suspend/devfreq_resume and
> cpufreq_suspend/cpufreq_resume are called in pairs.

So why is it better to do this than to make devfreq_resume() meet the
expectations?

> Signed-off-by: Vincent Wang <[email protected]>
> Signed-off-by: Samer Xie <[email protected]>
> Signed-off-by: Chunyan Zhang <[email protected]>
> ---
> drivers/base/power/main.c | 6 +++---
> 1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
> index fdd508a78ffd..eb3d987d43e0 100644
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -1866,9 +1866,6 @@ int dpm_suspend(pm_message_t state)
> trace_suspend_resume(TPS("dpm_suspend"), state.event, true);
> might_sleep();
>
> - devfreq_suspend();
> - cpufreq_suspend();
> -
> mutex_lock(&dpm_list_mtx);
> pm_transition = state;
> async_error = 0;
> @@ -1988,6 +1985,9 @@ int dpm_prepare(pm_message_t state)
> trace_suspend_resume(TPS("dpm_prepare"), state.event, true);
> might_sleep();
>
> + devfreq_suspend();
> + cpufreq_suspend();
> +
> /*
> * Give a chance for the known devices to complete their probes, before
> * disable probing of devices. This sync point is important at least
> --
> 2.20.1
>

2020-04-22 11:21:18

by Chunyan Zhang

[permalink] [raw]
Subject: Re: [PATCH] PM: sleep: call devfreq_suspend/resume and cpufreq_suspend/resume in pairs.

Hi Rafael,

(Behalf Of Vincent Wang)

Thanks for your comments, please see my answers below.

On Wed, 22 Apr 2020 at 17:05, Rafael J. Wysocki <[email protected]> wrote:
>
> On Wed, Apr 22, 2020 at 7:15 AM Chunyan Zhang <[email protected]> wrote:
> >
> > From: Vincent Wang <[email protected]>
> >
> > If dpm_prepare() fails in dpm_suspend_start(), dpm_suspend() can't be
> > called.
>
> That's correct.
>
> > And then, devfreq_suspend() and cpufreq_suspend() will not be
> > called in the suspend flow.
>
> Right.
>
> > But in the resiume flow, devfreq_resume() and cpufreq_resume() will
> > be called.
>
> Right, and they are expected to cope with the situation.
>
> > This patch will ensure that devfreq_suspend/devfreq_resume and
> > cpufreq_suspend/cpufreq_resume are called in pairs.
>
> So why is it better to do this than to make devfreq_resume() meet the
> expectations?

Yes,we found an issue with cpufreq schedutil governor on kernel4.14,
and I think the issue should haven't been changed on the latest
version of kernel.

In the function dpm_suspend_start(), dpm_suspend() would not be
exceuted if return error from device_prepare() [1]. So
cpufreq_cpufreq() will not be called, then
cpufreq_remove_update_util_hook() will not be called either, and so
cpufreq_update_util_data will not be NULL.

In the dpm resume flow, sugov_start() will be called, in which
sg_cpu.update_util will be set to 0.

And since cpufreq_update_util_data is not NULL, data->func will not be
set and is still NULL which actually is sg_cpu.update_util.

void cpufreq_add_update_util_hook(int cpu, struct update_util_data *data,
void (*func)(struct update_util_data *data, u64 time,
unsigned int flags))
{
[...]
if (WARN_ON(per_cpu(cpufreq_update_util_data, cpu)))
return;

data->func = func;
[...]
}

When cpufreq_update_util() is called by scheduler, there will be a
NULL pointer issue.


[1] https://elixir.bootlin.com/linux/v5.7-rc1/source/drivers/base/power/main.c#L2052


>
> > Signed-off-by: Vincent Wang <[email protected]>
> > Signed-off-by: Samer Xie <[email protected]>
> > Signed-off-by: Chunyan Zhang <[email protected]>
> > ---
> > drivers/base/power/main.c | 6 +++---
> > 1 file changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
> > index fdd508a78ffd..eb3d987d43e0 100644
> > --- a/drivers/base/power/main.c
> > +++ b/drivers/base/power/main.c
> > @@ -1866,9 +1866,6 @@ int dpm_suspend(pm_message_t state)
> > trace_suspend_resume(TPS("dpm_suspend"), state.event, true);
> > might_sleep();
> >
> > - devfreq_suspend();
> > - cpufreq_suspend();
> > -
> > mutex_lock(&dpm_list_mtx);
> > pm_transition = state;
> > async_error = 0;
> > @@ -1988,6 +1985,9 @@ int dpm_prepare(pm_message_t state)
> > trace_suspend_resume(TPS("dpm_prepare"), state.event, true);
> > might_sleep();
> >
> > + devfreq_suspend();
> > + cpufreq_suspend();
> > +
> > /*
> > * Give a chance for the known devices to complete their probes, before
> > * disable probing of devices. This sync point is important at least
> > --
> > 2.20.1
> >

2020-04-22 14:23:50

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH] PM: sleep: call devfreq_suspend/resume and cpufreq_suspend/resume in pairs.

On Wed, Apr 22, 2020 at 1:19 PM Chunyan Zhang <[email protected]> wrote:
>
> Hi Rafael,
>
> (Behalf Of Vincent Wang)
>
> Thanks for your comments, please see my answers below.
>
> On Wed, 22 Apr 2020 at 17:05, Rafael J. Wysocki <[email protected]> wrote:
> >
> > On Wed, Apr 22, 2020 at 7:15 AM Chunyan Zhang <[email protected]> wrote:
> > >
> > > From: Vincent Wang <[email protected]>
> > >
> > > If dpm_prepare() fails in dpm_suspend_start(), dpm_suspend() can't be
> > > called.
> >
> > That's correct.
> >
> > > And then, devfreq_suspend() and cpufreq_suspend() will not be
> > > called in the suspend flow.
> >
> > Right.
> >
> > > But in the resiume flow, devfreq_resume() and cpufreq_resume() will
> > > be called.
> >
> > Right, and they are expected to cope with the situation.
> >
> > > This patch will ensure that devfreq_suspend/devfreq_resume and
> > > cpufreq_suspend/cpufreq_resume are called in pairs.
> >
> > So why is it better to do this than to make devfreq_resume() meet the
> > expectations?
>
> Yes,we found an issue with cpufreq schedutil governor on kernel4.14,
> and I think the issue should haven't been changed on the latest
> version of kernel.
>
> In the function dpm_suspend_start(), dpm_suspend() would not be
> exceuted if return error from device_prepare() [1]. So
> cpufreq_cpufreq() will not be called,

I guess you mean cpufreq_suspend().

That should be OK .

> then cpufreq_remove_update_util_hook() will not be called either, and so
> cpufreq_update_util_data will not be NULL.
>
> In the dpm resume flow, sugov_start() will be called, in which
> sg_cpu.update_util will be set to 0.

Which code patch does this?

Surely not cpufreq_resume(), because that checks cpufreq_suspended which
cannot be set if cpufreq_suspend() has not been called (because it is the only
place setting cpufreq_suspended).

2020-04-23 02:45:10

by Chunyan Zhang

[permalink] [raw]
Subject: Re: [PATCH] PM: sleep: call devfreq_suspend/resume and cpufreq_suspend/resume in pairs.

On Wed, 22 Apr 2020 at 22:21, Rafael J. Wysocki <[email protected]> wrote:
>
> On Wed, Apr 22, 2020 at 1:19 PM Chunyan Zhang <[email protected]> wrote:
> >
> > Hi Rafael,
> >
> > (Behalf Of Vincent Wang)
> >
> > Thanks for your comments, please see my answers below.
> >
> > On Wed, 22 Apr 2020 at 17:05, Rafael J. Wysocki <[email protected]> wrote:
> > >
> > > On Wed, Apr 22, 2020 at 7:15 AM Chunyan Zhang <[email protected]> wrote:
> > > >
> > > > From: Vincent Wang <[email protected]>
> > > >
> > > > If dpm_prepare() fails in dpm_suspend_start(), dpm_suspend() can't be
> > > > called.
> > >
> > > That's correct.
> > >
> > > > And then, devfreq_suspend() and cpufreq_suspend() will not be
> > > > called in the suspend flow.
> > >
> > > Right.
> > >
> > > > But in the resiume flow, devfreq_resume() and cpufreq_resume() will
> > > > be called.
> > >
> > > Right, and they are expected to cope with the situation.
> > >
> > > > This patch will ensure that devfreq_suspend/devfreq_resume and
> > > > cpufreq_suspend/cpufreq_resume are called in pairs.
> > >
> > > So why is it better to do this than to make devfreq_resume() meet the
> > > expectations?
> >
> > Yes,we found an issue with cpufreq schedutil governor on kernel4.14,
> > and I think the issue should haven't been changed on the latest
> > version of kernel.
> >
> > In the function dpm_suspend_start(), dpm_suspend() would not be
> > exceuted if return error from device_prepare() [1]. So
> > cpufreq_cpufreq() will not be called,
>
> I guess you mean cpufreq_suspend().
>
> That should be OK .
>
> > then cpufreq_remove_update_util_hook() will not be called either, and so
> > cpufreq_update_util_data will not be NULL.
> >
> > In the dpm resume flow, sugov_start() will be called, in which
> > sg_cpu.update_util will be set to 0.
>
> Which code patch does this?
>
> Surely not cpufreq_resume(), because that checks cpufreq_suspended which
> cannot be set if cpufreq_suspend() has not been called (because it is the only
> place setting cpufreq_suspended).

Right, I saw that, then there's no issue indeed. I just need to
backport the patch which added checking of cpufreq_suspended to
cpufreq_resume.

Thanks for your review!