diff mbox series

[RESEND] PM: wakeup: Wakeup accounting for interrupts

Message ID 1643016384-11161-1-git-send-email-loic.poulain@linaro.org (mailing list archive)
State Changes Requested, archived
Headers show
Series [RESEND] PM: wakeup: Wakeup accounting for interrupts | expand

Commit Message

Loic Poulain Jan. 24, 2022, 9:26 a.m. UTC
Most of the time, system wakeup is caused by a wakeup-enabled
interrupt, but the accounting is not done for the related wakeup
source, causing 'wrong' values reported by device's wakeup attributes
and debugfs stats (debug/wakeup_sources).

This change reports a wakeup event for any wakeup-sources the irq is
attached with.

Note: This only works for drivers explicitly attaching the irq to
a given device (e.g. with dev_pm_set_wake_irq).

Note2: Some drivers call pm_wakeup_event() in their irq handler, but
not all, moreover, an interrupt can be disabled while being flagged
as wakeup source, and so accounting must be performed. This solution
ensures that accounting will always be done for the interrupt waking
up the host.

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
---
 drivers/base/power/wakeup.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

Comments

Rafael J. Wysocki Jan. 26, 2022, 6:22 p.m. UTC | #1
On Mon, Jan 24, 2022 at 10:14 AM Loic Poulain <loic.poulain@linaro.org> wrote:
>
> Most of the time, system wakeup is caused by a wakeup-enabled
> interrupt, but the accounting is not done for the related wakeup
> source, causing 'wrong' values reported by device's wakeup attributes
> and debugfs stats (debug/wakeup_sources).
>
> This change reports a wakeup event for any wakeup-sources the irq is
> attached with.
>
> Note: This only works for drivers explicitly attaching the irq to
> a given device (e.g. with dev_pm_set_wake_irq).
>
> Note2: Some drivers call pm_wakeup_event() in their irq handler, but
> not all, moreover, an interrupt can be disabled while being flagged
> as wakeup source, and so accounting must be performed. This solution
> ensures that accounting will always be done for the interrupt waking
> up the host.
>
> Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
> ---
>  drivers/base/power/wakeup.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
>
> diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
> index 99bda0da..2d75e057 100644
> --- a/drivers/base/power/wakeup.c
> +++ b/drivers/base/power/wakeup.c
> @@ -952,8 +952,19 @@ void pm_wakeup_clear(bool reset)
>  void pm_system_irq_wakeup(unsigned int irq_number)
>  {
>         if (pm_wakeup_irq == 0) {
> +               struct wakeup_source *ws;
> +               int srcuidx;
> +
>                 pm_wakeup_irq = irq_number;
>                 pm_system_wakeup();
> +
> +               /* wakeup accounting */
> +               srcuidx = srcu_read_lock(&wakeup_srcu);

This is called from interrupt context, so srcu_read_lock() cannot be used here.

> +               list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
> +                       if (ws->wakeirq && ws->wakeirq->irq == irq_number)
> +                               pm_wakeup_ws_event(ws, 0, false);
> +               }
> +               srcu_read_unlock(&wakeup_srcu, srcuidx);
>         }
>  }
>
> --
> 2.7.4
>
Loic Poulain Jan. 27, 2022, 9:02 a.m. UTC | #2
Hi Rafael,

On Wed, 26 Jan 2022 at 19:23, Rafael J. Wysocki <rafael@kernel.org> wrote:
>
> On Mon, Jan 24, 2022 at 10:14 AM Loic Poulain <loic.poulain@linaro.org> wrote:
> >
> > Most of the time, system wakeup is caused by a wakeup-enabled
> > interrupt, but the accounting is not done for the related wakeup
> > source, causing 'wrong' values reported by device's wakeup attributes
> > and debugfs stats (debug/wakeup_sources).
> >
> > This change reports a wakeup event for any wakeup-sources the irq is
> > attached with.
> >
> > Note: This only works for drivers explicitly attaching the irq to
> > a given device (e.g. with dev_pm_set_wake_irq).
> >
> > Note2: Some drivers call pm_wakeup_event() in their irq handler, but
> > not all, moreover, an interrupt can be disabled while being flagged
> > as wakeup source, and so accounting must be performed. This solution
> > ensures that accounting will always be done for the interrupt waking
> > up the host.
> >
> > Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
> > ---
> >  drivers/base/power/wakeup.c | 11 +++++++++++
> >  1 file changed, 11 insertions(+)
> >
> > diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
> > index 99bda0da..2d75e057 100644
> > --- a/drivers/base/power/wakeup.c
> > +++ b/drivers/base/power/wakeup.c
> > @@ -952,8 +952,19 @@ void pm_wakeup_clear(bool reset)
> >  void pm_system_irq_wakeup(unsigned int irq_number)
> >  {
> >         if (pm_wakeup_irq == 0) {
> > +               struct wakeup_source *ws;
> > +               int srcuidx;
> > +
> >                 pm_wakeup_irq = irq_number;
> >                 pm_system_wakeup();
> > +
> > +               /* wakeup accounting */
> > +               srcuidx = srcu_read_lock(&wakeup_srcu);
>
> This is called from interrupt context, so srcu_read_lock() cannot be used here.


AFAIU from srcu.h, it is not prohibited, right? and we are not
blocking while locked here.

Regards,
Loic

>
>
> > +               list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
> > +                       if (ws->wakeirq && ws->wakeirq->irq == irq_number)
> > +                               pm_wakeup_ws_event(ws, 0, false);
> > +               }
> > +               srcu_read_unlock(&wakeup_srcu, srcuidx);
> >         }
> >  }
> >
> > --
> > 2.7.4
> >
Rafael J. Wysocki Jan. 27, 2022, 7:04 p.m. UTC | #3
On Thu, Jan 27, 2022 at 9:51 AM Loic Poulain <loic.poulain@linaro.org> wrote:
>
> Hi Rafael,
>
> On Wed, 26 Jan 2022 at 19:23, Rafael J. Wysocki <rafael@kernel.org> wrote:
> >
> > On Mon, Jan 24, 2022 at 10:14 AM Loic Poulain <loic.poulain@linaro.org> wrote:
> > >
> > > Most of the time, system wakeup is caused by a wakeup-enabled
> > > interrupt, but the accounting is not done for the related wakeup
> > > source, causing 'wrong' values reported by device's wakeup attributes
> > > and debugfs stats (debug/wakeup_sources).
> > >
> > > This change reports a wakeup event for any wakeup-sources the irq is
> > > attached with.
> > >
> > > Note: This only works for drivers explicitly attaching the irq to
> > > a given device (e.g. with dev_pm_set_wake_irq).
> > >
> > > Note2: Some drivers call pm_wakeup_event() in their irq handler, but
> > > not all, moreover, an interrupt can be disabled while being flagged
> > > as wakeup source, and so accounting must be performed. This solution
> > > ensures that accounting will always be done for the interrupt waking
> > > up the host.
> > >
> > > Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
> > > ---
> > >  drivers/base/power/wakeup.c | 11 +++++++++++
> > >  1 file changed, 11 insertions(+)
> > >
> > > diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
> > > index 99bda0da..2d75e057 100644
> > > --- a/drivers/base/power/wakeup.c
> > > +++ b/drivers/base/power/wakeup.c
> > > @@ -952,8 +952,19 @@ void pm_wakeup_clear(bool reset)
> > >  void pm_system_irq_wakeup(unsigned int irq_number)
> > >  {
> > >         if (pm_wakeup_irq == 0) {
> > > +               struct wakeup_source *ws;
> > > +               int srcuidx;
> > > +
> > >                 pm_wakeup_irq = irq_number;
> > >                 pm_system_wakeup();
> > > +
> > > +               /* wakeup accounting */
> > > +               srcuidx = srcu_read_lock(&wakeup_srcu);
> >
> > This is called from interrupt context, so srcu_read_lock() cannot be used here.
>
>
> AFAIU from srcu.h, it is not prohibited, right? and we are not
> blocking while locked here.

OK, you can do that if you release it from the same context.

There are other concerns regarding this change, though.

First off, it adds overhead for all systems, but the benefit is there
only for the systems where wake IRQs are used.

Second, it may lead to reporting the same wakeup event twice in a row
if the driver decides to do that too.  Is this not a problem?

> > > +               list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
> > > +                       if (ws->wakeirq && ws->wakeirq->irq == irq_number)
> > > +                               pm_wakeup_ws_event(ws, 0, false);
> > > +               }
> > > +               srcu_read_unlock(&wakeup_srcu, srcuidx);
> > >         }
> > >  }
> > >
> > > --
> > > 2.7.4
> > >
Loic Poulain Jan. 28, 2022, 10:08 a.m. UTC | #4
On Thu, 27 Jan 2022 at 20:05, Rafael J. Wysocki <rafael@kernel.org> wrote:
>
> On Thu, Jan 27, 2022 at 9:51 AM Loic Poulain <loic.poulain@linaro.org> wrote:
> >
> > Hi Rafael,
> >
> > On Wed, 26 Jan 2022 at 19:23, Rafael J. Wysocki <rafael@kernel.org> wrote:
> > >
> > > On Mon, Jan 24, 2022 at 10:14 AM Loic Poulain <loic.poulain@linaro.org> wrote:
> > > >
> > > > Most of the time, system wakeup is caused by a wakeup-enabled
> > > > interrupt, but the accounting is not done for the related wakeup
> > > > source, causing 'wrong' values reported by device's wakeup attributes
> > > > and debugfs stats (debug/wakeup_sources).
> > > >
> > > > This change reports a wakeup event for any wakeup-sources the irq is
> > > > attached with.
> > > >
> > > > Note: This only works for drivers explicitly attaching the irq to
> > > > a given device (e.g. with dev_pm_set_wake_irq).
> > > >
> > > > Note2: Some drivers call pm_wakeup_event() in their irq handler, but
> > > > not all, moreover, an interrupt can be disabled while being flagged
> > > > as wakeup source, and so accounting must be performed. This solution
> > > > ensures that accounting will always be done for the interrupt waking
> > > > up the host.
> > > >
> > > > Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
> > > > ---
> > > >  drivers/base/power/wakeup.c | 11 +++++++++++
> > > >  1 file changed, 11 insertions(+)
> > > >
> > > > diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
> > > > index 99bda0da..2d75e057 100644
> > > > --- a/drivers/base/power/wakeup.c
> > > > +++ b/drivers/base/power/wakeup.c
> > > > @@ -952,8 +952,19 @@ void pm_wakeup_clear(bool reset)
> > > >  void pm_system_irq_wakeup(unsigned int irq_number)
> > > >  {
> > > >         if (pm_wakeup_irq == 0) {
> > > > +               struct wakeup_source *ws;
> > > > +               int srcuidx;
> > > > +
> > > >                 pm_wakeup_irq = irq_number;
> > > >                 pm_system_wakeup();
> > > > +
> > > > +               /* wakeup accounting */
> > > > +               srcuidx = srcu_read_lock(&wakeup_srcu);
> > >
> > > This is called from interrupt context, so srcu_read_lock() cannot be used here.
> >
> >
> > AFAIU from srcu.h, it is not prohibited, right? and we are not
> > blocking while locked here.
>
> OK, you can do that if you release it from the same context.
>
> There are other concerns regarding this change, though.
>
> First off, it adds overhead for all systems, but the benefit is there
> only for the systems where wake IRQs are used.

It adds very little overhead for interrupts with armed wakeup, during
system suspend(ing/ed) only, other IRQs are not affected.

>
> Second, it may lead to reporting the same wakeup event twice in a row
> if the driver decides to do that too.  Is this not a problem?

That's a legitimate point, but I don't see it as a big concern
compared to not recording the event at all. If a driver deliberately
attaches an interrupt to a wake source, it seems sane to expect that
this interrupt will cause a corresponding wakeup event (should
probably be documented), whatever the driver's irq handler is doing.


>
> > > > +               list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
> > > > +                       if (ws->wakeirq && ws->wakeirq->irq == irq_number)
> > > > +                               pm_wakeup_ws_event(ws, 0, false);
> > > > +               }
> > > > +               srcu_read_unlock(&wakeup_srcu, srcuidx);
> > > >         }
> > > >  }
> > > >
> > > > --
> > > > 2.7.4
> > > >
Rafael J. Wysocki Feb. 16, 2022, 4:59 p.m. UTC | #5
Sorry for the delay.

On Fri, Jan 28, 2022 at 10:55 AM Loic Poulain <loic.poulain@linaro.org> wrote:
>
> On Thu, 27 Jan 2022 at 20:05, Rafael J. Wysocki <rafael@kernel.org> wrote:
> >
> > On Thu, Jan 27, 2022 at 9:51 AM Loic Poulain <loic.poulain@linaro.org> wrote:
> > >
> > > Hi Rafael,
> > >
> > > On Wed, 26 Jan 2022 at 19:23, Rafael J. Wysocki <rafael@kernel.org> wrote:
> > > >
> > > > On Mon, Jan 24, 2022 at 10:14 AM Loic Poulain <loic.poulain@linaro.org> wrote:
> > > > >
> > > > > Most of the time, system wakeup is caused by a wakeup-enabled
> > > > > interrupt, but the accounting is not done for the related wakeup
> > > > > source, causing 'wrong' values reported by device's wakeup attributes
> > > > > and debugfs stats (debug/wakeup_sources).
> > > > >
> > > > > This change reports a wakeup event for any wakeup-sources the irq is
> > > > > attached with.
> > > > >
> > > > > Note: This only works for drivers explicitly attaching the irq to
> > > > > a given device (e.g. with dev_pm_set_wake_irq).
> > > > >
> > > > > Note2: Some drivers call pm_wakeup_event() in their irq handler, but
> > > > > not all, moreover, an interrupt can be disabled while being flagged
> > > > > as wakeup source, and so accounting must be performed. This solution
> > > > > ensures that accounting will always be done for the interrupt waking
> > > > > up the host.
> > > > >
> > > > > Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
> > > > > ---
> > > > >  drivers/base/power/wakeup.c | 11 +++++++++++
> > > > >  1 file changed, 11 insertions(+)
> > > > >
> > > > > diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
> > > > > index 99bda0da..2d75e057 100644
> > > > > --- a/drivers/base/power/wakeup.c
> > > > > +++ b/drivers/base/power/wakeup.c
> > > > > @@ -952,8 +952,19 @@ void pm_wakeup_clear(bool reset)
> > > > >  void pm_system_irq_wakeup(unsigned int irq_number)
> > > > >  {
> > > > >         if (pm_wakeup_irq == 0) {
> > > > > +               struct wakeup_source *ws;
> > > > > +               int srcuidx;
> > > > > +
> > > > >                 pm_wakeup_irq = irq_number;
> > > > >                 pm_system_wakeup();
> > > > > +
> > > > > +               /* wakeup accounting */
> > > > > +               srcuidx = srcu_read_lock(&wakeup_srcu);
> > > >
> > > > This is called from interrupt context, so srcu_read_lock() cannot be used here.
> > >
> > >
> > > AFAIU from srcu.h, it is not prohibited, right? and we are not
> > > blocking while locked here.
> >
> > OK, you can do that if you release it from the same context.
> >
> > There are other concerns regarding this change, though.
> >
> > First off, it adds overhead for all systems, but the benefit is there
> > only for the systems where wake IRQs are used.
>
> It adds very little overhead for interrupts with armed wakeup, during
> system suspend(ing/ed) only, other IRQs are not affected.
>
> >
> > Second, it may lead to reporting the same wakeup event twice in a row
> > if the driver decides to do that too.  Is this not a problem?
>
> That's a legitimate point, but I don't see it as a big concern
> compared to not recording the event at all. If a driver deliberately
> attaches an interrupt to a wake source, it seems sane to expect that
> this interrupt will cause a corresponding wakeup event (should
> probably be documented), whatever the driver's irq handler is doing.

This needs to be rebased on top of 5.17-rc4 after a somewhat related
bug fix that went into it.

Moreover, I think that you'd want to do the below for all of the
wakeup interrupts that trigger, not just for the first one.

Also, the problem mentioned in the changelog is not limited to devices
having dedicated wakeup IRQs, but the proposed approach to address it
is.  Why are the other cases not relevant?

> >
> > > > > +               list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
> > > > > +                       if (ws->wakeirq && ws->wakeirq->irq == irq_number)
> > > > > +                               pm_wakeup_ws_event(ws, 0, false);
> > > > > +               }
> > > > > +               srcu_read_unlock(&wakeup_srcu, srcuidx);
> > > > >         }
> > > > >  }
> > > > >
> > > > > --
> > > > > 2.7.4
> > > > >
Loic Poulain Feb. 16, 2022, 5:48 p.m. UTC | #6
On Wed, 16 Feb 2022 at 17:59, Rafael J. Wysocki <rafael@kernel.org> wrote:
>
> Sorry for the delay.
>
> On Fri, Jan 28, 2022 at 10:55 AM Loic Poulain <loic.poulain@linaro.org> wrote:
> >
> > On Thu, 27 Jan 2022 at 20:05, Rafael J. Wysocki <rafael@kernel.org> wrote:
> > >
> > > On Thu, Jan 27, 2022 at 9:51 AM Loic Poulain <loic.poulain@linaro.org> wrote:
> > > >
> > > > Hi Rafael,
> > > >
> > > > On Wed, 26 Jan 2022 at 19:23, Rafael J. Wysocki <rafael@kernel.org> wrote:
> > > > >
> > > > > On Mon, Jan 24, 2022 at 10:14 AM Loic Poulain <loic.poulain@linaro.org> wrote:
> > > > > >
> > > > > > Most of the time, system wakeup is caused by a wakeup-enabled
> > > > > > interrupt, but the accounting is not done for the related wakeup
> > > > > > source, causing 'wrong' values reported by device's wakeup attributes
> > > > > > and debugfs stats (debug/wakeup_sources).
> > > > > >
> > > > > > This change reports a wakeup event for any wakeup-sources the irq is
> > > > > > attached with.
> > > > > >
> > > > > > Note: This only works for drivers explicitly attaching the irq to
> > > > > > a given device (e.g. with dev_pm_set_wake_irq).
> > > > > >
> > > > > > Note2: Some drivers call pm_wakeup_event() in their irq handler, but
> > > > > > not all, moreover, an interrupt can be disabled while being flagged
> > > > > > as wakeup source, and so accounting must be performed. This solution
> > > > > > ensures that accounting will always be done for the interrupt waking
> > > > > > up the host.
> > > > > >
> > > > > > Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
> > > > > > ---
> > > > > >  drivers/base/power/wakeup.c | 11 +++++++++++
> > > > > >  1 file changed, 11 insertions(+)
> > > > > >
> > > > > > diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
> > > > > > index 99bda0da..2d75e057 100644
> > > > > > --- a/drivers/base/power/wakeup.c
> > > > > > +++ b/drivers/base/power/wakeup.c
> > > > > > @@ -952,8 +952,19 @@ void pm_wakeup_clear(bool reset)
> > > > > >  void pm_system_irq_wakeup(unsigned int irq_number)
> > > > > >  {
> > > > > >         if (pm_wakeup_irq == 0) {
> > > > > > +               struct wakeup_source *ws;
> > > > > > +               int srcuidx;
> > > > > > +
> > > > > >                 pm_wakeup_irq = irq_number;
> > > > > >                 pm_system_wakeup();
> > > > > > +
> > > > > > +               /* wakeup accounting */
> > > > > > +               srcuidx = srcu_read_lock(&wakeup_srcu);
> > > > >
> > > > > This is called from interrupt context, so srcu_read_lock() cannot be used here.
> > > >
> > > >
> > > > AFAIU from srcu.h, it is not prohibited, right? and we are not
> > > > blocking while locked here.
> > >
> > > OK, you can do that if you release it from the same context.
> > >
> > > There are other concerns regarding this change, though.
> > >
> > > First off, it adds overhead for all systems, but the benefit is there
> > > only for the systems where wake IRQs are used.
> >
> > It adds very little overhead for interrupts with armed wakeup, during
> > system suspend(ing/ed) only, other IRQs are not affected.
> >
> > >
> > > Second, it may lead to reporting the same wakeup event twice in a row
> > > if the driver decides to do that too.  Is this not a problem?
> >
> > That's a legitimate point, but I don't see it as a big concern
> > compared to not recording the event at all. If a driver deliberately
> > attaches an interrupt to a wake source, it seems sane to expect that
> > this interrupt will cause a corresponding wakeup event (should
> > probably be documented), whatever the driver's irq handler is doing.
>
> This needs to be rebased on top of 5.17-rc4 after a somewhat related
> bug fix that went into it.

Ok

>
>
> Moreover, I think that you'd want to do the below for all of the
> wakeup interrupts that trigger, not just for the first one.

Yes you're right, it makes sense.

>
>
> Also, the problem mentioned in the changelog is not limited to devices
> having dedicated wakeup IRQs, but the proposed approach to address it
> is.  Why are the other cases not relevant?

Not sure to understand what other cases you are referring to? here we
ensure that interrupts bound to a wakeup-source trigger the
corresponding wakeup event. So the ones configured via one of the
dev_pm_set_(dedicated_)wake_irq functions. But many drivers do not
explicitly attach IRQ as device's wake-irq, so there is no attached
wakeup-source to manage in that case.


>
>
> > >
> > > > > > +               list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
> > > > > > +                       if (ws->wakeirq && ws->wakeirq->irq == irq_number)
> > > > > > +                               pm_wakeup_ws_event(ws, 0, false);
> > > > > > +               }
> > > > > > +               srcu_read_unlock(&wakeup_srcu, srcuidx);
> > > > > >         }
> > > > > >  }
> > > > > >
> > > > > > --
> > > > > > 2.7.4
> > > > > >
diff mbox series

Patch

diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 99bda0da..2d75e057 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -952,8 +952,19 @@  void pm_wakeup_clear(bool reset)
 void pm_system_irq_wakeup(unsigned int irq_number)
 {
 	if (pm_wakeup_irq == 0) {
+		struct wakeup_source *ws;
+		int srcuidx;
+
 		pm_wakeup_irq = irq_number;
 		pm_system_wakeup();
+
+		/* wakeup accounting */
+		srcuidx = srcu_read_lock(&wakeup_srcu);
+		list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+			if (ws->wakeirq && ws->wakeirq->irq == irq_number)
+				pm_wakeup_ws_event(ws, 0, false);
+		}
+		srcu_read_unlock(&wakeup_srcu, srcuidx);
 	}
 }