[PATCH v3 1/4] pmdomain: core: Introduce device_set/get_out_band_wakeup()

Peng Fan posted 4 patches 1 month ago
[PATCH v3 1/4] pmdomain: core: Introduce device_set/get_out_band_wakeup()
Posted by Peng Fan 1 month ago
For some cases, a device could still wakeup the system even if its power
domain is in off state, because the device's wakeup hardware logic is
in an always-on domain.

To support this case, introduce device_set/get_out_band_wakeup() to
allow device drivers to control the behaviour in genpd for a device
that is attached to it.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/pmdomain/core.c   |  6 ++++--
 include/linux/pm.h        |  1 +
 include/linux/pm_wakeup.h | 17 +++++++++++++++++
 3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
index 0006ab3d078972cc72a6dd22a2144fb31443e3da..8e37758cea88a9ee051ad9fb13bdd3feb4f8745e 100644
--- a/drivers/pmdomain/core.c
+++ b/drivers/pmdomain/core.c
@@ -1549,7 +1549,8 @@ static int genpd_finish_suspend(struct device *dev,
 	if (ret)
 		return ret;
 
-	if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
+	if (device_awake_path(dev) && genpd_is_active_wakeup(genpd) &&
+	    !device_get_out_band_wakeup(dev))
 		return 0;
 
 	if (genpd->dev_ops.stop && genpd->dev_ops.start &&
@@ -1604,7 +1605,8 @@ static int genpd_finish_resume(struct device *dev,
 	if (IS_ERR(genpd))
 		return -EINVAL;
 
-	if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
+	if (device_awake_path(dev) && genpd_is_active_wakeup(genpd) &&
+	    !device_get_out_band_wakeup(dev))
 		return resume_noirq(dev);
 
 	genpd_lock(genpd);
diff --git a/include/linux/pm.h b/include/linux/pm.h
index cc7b2dc28574c24ece2f651352d4d23ecaf15f31..5b28a4f2e87e2aa34acc709e146ce729acace344 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -684,6 +684,7 @@ struct dev_pm_info {
 	bool			smart_suspend:1;	/* Owned by the PM core */
 	bool			must_resume:1;		/* Owned by the PM core */
 	bool			may_skip_resume:1;	/* Set by subsystems */
+	bool			out_band_wakeup:1;
 	bool			strict_midlayer:1;
 #else
 	bool			should_wakeup:1;
diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
index c838b4a30f876ef5a66972d16f461cfba9ff2814..c461c7edef6f7927d696b7d18b59a6a1147f53a3 100644
--- a/include/linux/pm_wakeup.h
+++ b/include/linux/pm_wakeup.h
@@ -94,6 +94,16 @@ static inline void device_set_wakeup_path(struct device *dev)
 	dev->power.wakeup_path = true;
 }
 
+static inline void device_set_out_band_wakeup(struct device *dev, bool capable)
+{
+	dev->power.out_band_wakeup = capable;
+}
+
+static inline bool device_get_out_band_wakeup(struct device *dev)
+{
+	return dev->power.out_band_wakeup;
+}
+
 /* drivers/base/power/wakeup.c */
 extern struct wakeup_source *wakeup_source_register(struct device *dev,
 						    const char *name);
@@ -162,6 +172,13 @@ static inline bool device_wakeup_path(struct device *dev)
 
 static inline void device_set_wakeup_path(struct device *dev) {}
 
+static inline void device_set_out_band_wakeup(struct device *dev, bool capable) {}
+
+static inline bool device_get_out_band_wakeup(struct device *dev)
+{
+	return false;
+}
+
 static inline void __pm_stay_awake(struct wakeup_source *ws) {}
 
 static inline void pm_stay_awake(struct device *dev) {}

-- 
2.37.1
Re: [PATCH v3 1/4] pmdomain: core: Introduce device_set/get_out_band_wakeup()
Posted by Ulf Hansson 2 weeks ago
On Tue, 2 Sept 2025 at 05:33, Peng Fan <peng.fan@nxp.com> wrote:
>
> For some cases, a device could still wakeup the system even if its power
> domain is in off state, because the device's wakeup hardware logic is
> in an always-on domain.
>
> To support this case, introduce device_set/get_out_band_wakeup() to
> allow device drivers to control the behaviour in genpd for a device
> that is attached to it.

Would you mind trying to extend/clarify this commit-msg a bit more, to
make the benefit more clear.

For example, today we may be wasting energy, by unnecessarily keeping
PM domains powered-on during system-wide suspend, when a device has
been enabled for system-wakeup...

In regards to terminology, I would appreciate if we could use
"system-wakeup" and "out-band system-wakeup logic" and "system-wide
suspend".

>
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> ---
>  drivers/pmdomain/core.c   |  6 ++++--
>  include/linux/pm.h        |  1 +
>  include/linux/pm_wakeup.h | 17 +++++++++++++++++

Please split this into two separate patches.

>  3 files changed, 22 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
> index 0006ab3d078972cc72a6dd22a2144fb31443e3da..8e37758cea88a9ee051ad9fb13bdd3feb4f8745e 100644
> --- a/drivers/pmdomain/core.c
> +++ b/drivers/pmdomain/core.c
> @@ -1549,7 +1549,8 @@ static int genpd_finish_suspend(struct device *dev,
>         if (ret)
>                 return ret;
>
> -       if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
> +       if (device_awake_path(dev) && genpd_is_active_wakeup(genpd) &&
> +           !device_get_out_band_wakeup(dev))
>                 return 0;
>
>         if (genpd->dev_ops.stop && genpd->dev_ops.start &&
> @@ -1604,7 +1605,8 @@ static int genpd_finish_resume(struct device *dev,
>         if (IS_ERR(genpd))
>                 return -EINVAL;
>
> -       if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
> +       if (device_awake_path(dev) && genpd_is_active_wakeup(genpd) &&
> +           !device_get_out_band_wakeup(dev))
>                 return resume_noirq(dev);
>
>         genpd_lock(genpd);
> diff --git a/include/linux/pm.h b/include/linux/pm.h
> index cc7b2dc28574c24ece2f651352d4d23ecaf15f31..5b28a4f2e87e2aa34acc709e146ce729acace344 100644
> --- a/include/linux/pm.h
> +++ b/include/linux/pm.h
> @@ -684,6 +684,7 @@ struct dev_pm_info {
>         bool                    smart_suspend:1;        /* Owned by the PM core */
>         bool                    must_resume:1;          /* Owned by the PM core */
>         bool                    may_skip_resume:1;      /* Set by subsystems */
> +       bool                    out_band_wakeup:1;
>         bool                    strict_midlayer:1;
>  #else
>         bool                    should_wakeup:1;
> diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
> index c838b4a30f876ef5a66972d16f461cfba9ff2814..c461c7edef6f7927d696b7d18b59a6a1147f53a3 100644
> --- a/include/linux/pm_wakeup.h
> +++ b/include/linux/pm_wakeup.h
> @@ -94,6 +94,16 @@ static inline void device_set_wakeup_path(struct device *dev)
>         dev->power.wakeup_path = true;
>  }
>
> +static inline void device_set_out_band_wakeup(struct device *dev, bool capable)
> +{
> +       dev->power.out_band_wakeup = capable;

I suggest we drop the bool as in-parameter and just do:
dev->power.out_band_wakeup = true;

Moreover, I think we should clear the flag in device_prepare(), next
to where dev->power.wakeup_path is cleared.

This makes the behavior better aligned for users of these flags.

> +}
> +
> +static inline bool device_get_out_band_wakeup(struct device *dev)

Nitpick: I would rename this into device_out_band_wakeup(). At least
the "get" part is a confusing in my opinion, as indicates there is
reference taken too.

> +{
> +       return dev->power.out_band_wakeup;
> +}
> +
>  /* drivers/base/power/wakeup.c */
>  extern struct wakeup_source *wakeup_source_register(struct device *dev,
>                                                     const char *name);
> @@ -162,6 +172,13 @@ static inline bool device_wakeup_path(struct device *dev)
>
>  static inline void device_set_wakeup_path(struct device *dev) {}
>
> +static inline void device_set_out_band_wakeup(struct device *dev, bool capable) {}
> +
> +static inline bool device_get_out_band_wakeup(struct device *dev)
> +{
> +       return false;
> +}
> +
>  static inline void __pm_stay_awake(struct wakeup_source *ws) {}
>
>  static inline void pm_stay_awake(struct device *dev) {}
>
> --
> 2.37.1
>

Otherwise, from an overall functionality point of view, this makes sense to me!

Kind regards
Uffe
Re: [PATCH v3 1/4] pmdomain: core: Introduce device_set/get_out_band_wakeup()
Posted by Dhruva Gole 2 weeks, 1 day ago
On Sep 02, 2025 at 11:33:00 +0800, Peng Fan wrote:
> For some cases, a device could still wakeup the system even if its power
> domain is in off state, because the device's wakeup hardware logic is
> in an always-on domain.
> 
> To support this case, introduce device_set/get_out_band_wakeup() to
> allow device drivers to control the behaviour in genpd for a device
> that is attached to it.
> 

Thinking more into it, to me it seems like if the intent here is to only
allow the device drivers to figure out whether they should be or not be
executing the suspend/resume_noirqs then that can still be checked by
wisely using the device set_wakeup APIs in the driver itself.

Not sure why this patch should be necessary for a
driver to execute the suspend_noirq or not. That decision can very well
be taken inside the driver's suspend resume_noirq hooks based on wakeup
capability and wake_enabled statuses.

Just a pseudo code:
```
driver_suspend_noirq () {
	if (device_may_wakeup()) {
		// do the sequence where the power domain might get turned off
		// but like you say device can do some out band wakeup
		return XXX;
	}
	// regular suspend sequence here... maybe inband wakeup config / clk
	// disable etc...
}
 ```

And something similar in resume_noirq?

Just need to make sure that the probe func does the
device_set_wakeup_enable or capable stuff correctly as per your H/w and
wakeup requirements...


-- 
Best regards,
Dhruva Gole
Texas Instruments Incorporated
Re: [PATCH v3 1/4] pmdomain: core: Introduce device_set/get_out_band_wakeup()
Posted by Peng Fan 2 weeks ago
Hi Dhruva,

On Thu, Sep 18, 2025 at 03:29:50PM +0530, Dhruva Gole wrote:
>On Sep 02, 2025 at 11:33:00 +0800, Peng Fan wrote:
>> For some cases, a device could still wakeup the system even if its power
>> domain is in off state, because the device's wakeup hardware logic is
>> in an always-on domain.
>> 
>> To support this case, introduce device_set/get_out_band_wakeup() to
>> allow device drivers to control the behaviour in genpd for a device
>> that is attached to it.
>> 
>
>Thinking more into it, to me it seems like if the intent here is to only
>allow the device drivers to figure out whether they should be or not be
>executing the suspend/resume_noirqs then that can still be checked by
>wisely using the device set_wakeup APIs in the driver itself.
>
>Not sure why this patch should be necessary for a
>driver to execute the suspend_noirq or not. That decision can very well
>be taken inside the driver's suspend resume_noirq hooks based on wakeup
>capability and wake_enabled statuses.

I should join today's SCMI meeting, but something else caught me (:

Thanks for looking into this. 

In genpd_suspend_finish, genpd_sync_power_off will be called if
"(device_awake_path(dev) && genpd_is_active_wakeup(genpd))" is false.
So if the device is enabled wakeup, the genpd will not be turned off because
the check return true.

But to i.MX, if the device is configured as wakeup source, we still need to
power off the power domain, because the device has out-of-band wakeup logic.

This patch is to make sure the power domain could be powered off in
suspend flow and powered up in resume flow.

Thanks,
Peng

>
>Just a pseudo code:
>```
>driver_suspend_noirq () {
>	if (device_may_wakeup()) {
>		// do the sequence where the power domain might get turned off
>		// but like you say device can do some out band wakeup
>		return XXX;
>	}
>	// regular suspend sequence here... maybe inband wakeup config / clk
>	// disable etc...
>}
> ```
>
>And something similar in resume_noirq?
>
>Just need to make sure that the probe func does the
>device_set_wakeup_enable or capable stuff correctly as per your H/w and
>wakeup requirements...
>
>
>-- 
>Best regards,
>Dhruva Gole
>Texas Instruments Incorporated
Re: [PATCH v3 1/4] pmdomain: core: Introduce device_set/get_out_band_wakeup()
Posted by Dhruva Gole 2 weeks ago
Hi Peng,

On Sep 18, 2025 at 21:12:30 +0800, Peng Fan wrote:
> Hi Dhruva,
> 
> On Thu, Sep 18, 2025 at 03:29:50PM +0530, Dhruva Gole wrote:
> >On Sep 02, 2025 at 11:33:00 +0800, Peng Fan wrote:
> >> For some cases, a device could still wakeup the system even if its power
> >> domain is in off state, because the device's wakeup hardware logic is
> >> in an always-on domain.
> >> 
> >> To support this case, introduce device_set/get_out_band_wakeup() to
> >> allow device drivers to control the behaviour in genpd for a device
> >> that is attached to it.
> >> 
> >
> >Thinking more into it, to me it seems like if the intent here is to only
> >allow the device drivers to figure out whether they should be or not be
> >executing the suspend/resume_noirqs then that can still be checked by
> >wisely using the device set_wakeup APIs in the driver itself.
> >
> >Not sure why this patch should be necessary for a
> >driver to execute the suspend_noirq or not. That decision can very well
> >be taken inside the driver's suspend resume_noirq hooks based on wakeup
> >capability and wake_enabled statuses.
> 
> I should join today's SCMI meeting, but something else caught me (:

It's alright, maybe see you in the next one ;)

> 
> Thanks for looking into this. 
> 
> In genpd_suspend_finish, genpd_sync_power_off will be called if
> "(device_awake_path(dev) && genpd_is_active_wakeup(genpd))" is false.
> So if the device is enabled wakeup, the genpd will not be turned off because
> the check return true.

Umm I think this device_awake_path stuff is only going to be true when
someone calls device_set_wakeup_path, I don't think it is going to
return true for a wakeup_capable device. I know all these "wakeup"
terminology and APIs have become all too confusing :( , so maybe Ulf can
correct me.
I maybe misremembering, but I have seen in some cases where a driver may
have marked itself wakeup_capable but the suspend hooks still do get
called... So your concern about genpd_sync_power_off not being called
due to wakeup capable device driver may not be valid... Again please
feel to correct me if I am wrong.

Did you also look at the wake IRQ stuff I mentioned?
In the path you're talking about it just checks
device_awake_path(dev) && genpd_is_active_wakeup(genpd)
However if the device irq is just marked as a wake IRQ, I don't think
that is checked anywhere in this path. So definitely if the IRQ of your
device is set as a wake IRQ, it will still get suspended and resumed as
usual and that's what you want right?


> 
> But to i.MX, if the device is configured as wakeup source, we still need to
> power off the power domain, because the device has out-of-band wakeup logic.
> 
> This patch is to make sure the power domain could be powered off in
> suspend flow and powered up in resume flow.
> 
> Thanks,
> Peng
> 
> >
> >Just a pseudo code:
> >```
> >driver_suspend_noirq () {
> >	if (device_may_wakeup()) {
> >		// do the sequence where the power domain might get turned off
> >		// but like you say device can do some out band wakeup
> >		return XXX;
> >	}
> >	// regular suspend sequence here... maybe inband wakeup config / clk
> >	// disable etc...
> >}
> > ```
> >
> >And something similar in resume_noirq?
> >
> >Just need to make sure that the probe func does the
> >device_set_wakeup_enable or capable stuff correctly as per your H/w and
> >wakeup requirements...
> >
> >
> >-- 
> >Best regards,
> >Dhruva Gole
> >Texas Instruments Incorporated

-- 
Best regards,
Dhruva Gole
Texas Instruments Incorporated
Re: [PATCH v3 1/4] pmdomain: core: Introduce device_set/get_out_band_wakeup()
Posted by Ulf Hansson 2 weeks ago
On Thu, 18 Sept 2025 at 15:40, Dhruva Gole <d-gole@ti.com> wrote:
>
> Hi Peng,
>
> On Sep 18, 2025 at 21:12:30 +0800, Peng Fan wrote:
> > Hi Dhruva,
> >
> > On Thu, Sep 18, 2025 at 03:29:50PM +0530, Dhruva Gole wrote:
> > >On Sep 02, 2025 at 11:33:00 +0800, Peng Fan wrote:
> > >> For some cases, a device could still wakeup the system even if its power
> > >> domain is in off state, because the device's wakeup hardware logic is
> > >> in an always-on domain.
> > >>
> > >> To support this case, introduce device_set/get_out_band_wakeup() to
> > >> allow device drivers to control the behaviour in genpd for a device
> > >> that is attached to it.
> > >>
> > >
> > >Thinking more into it, to me it seems like if the intent here is to only
> > >allow the device drivers to figure out whether they should be or not be
> > >executing the suspend/resume_noirqs then that can still be checked by
> > >wisely using the device set_wakeup APIs in the driver itself.
> > >
> > >Not sure why this patch should be necessary for a
> > >driver to execute the suspend_noirq or not. That decision can very well
> > >be taken inside the driver's suspend resume_noirq hooks based on wakeup
> > >capability and wake_enabled statuses.
> >
> > I should join today's SCMI meeting, but something else caught me (:
>
> It's alright, maybe see you in the next one ;)
>
> >
> > Thanks for looking into this.
> >
> > In genpd_suspend_finish, genpd_sync_power_off will be called if
> > "(device_awake_path(dev) && genpd_is_active_wakeup(genpd))" is false.
> > So if the device is enabled wakeup, the genpd will not be turned off because
> > the check return true.
>
> Umm I think this device_awake_path stuff is only going to be true when
> someone calls device_set_wakeup_path, I don't think it is going to
> return true for a wakeup_capable device. I know all these "wakeup"
> terminology and APIs have become all too confusing :( , so maybe Ulf can
> correct me.

The PM core checks device_may_wakeup() in device_suspend() and then
sets dev->power.wakeup_path = true;

The device_set_awake_path() and device_awake_path(), is to allow
drivers/subsystems to enforce its device to stay powered-on during
system-wide suspend. This may be needed even if the device isn't
configured to deliver system-wakeups.

> I maybe misremembering, but I have seen in some cases where a driver may
> have marked itself wakeup_capable but the suspend hooks still do get
> called... So your concern about genpd_sync_power_off not being called
> due to wakeup capable device driver may not be valid... Again please
> feel to correct me if I am wrong.

The system PM callbacks should get called no matter what.

The problem Peng pointing out, is when genpd_suspend_noirq() (which
calls genpd_finish_suspend()) is called for a device that is attached
to a genpd, we may end up bailing out, preventing the power-off for
its PM domain, while it may be perfectly fine to allow the PM domain
to be powered-off.

The particular code we are looking at, is in genpd_finish_suspend():

        if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
                return 0;

>
> Did you also look at the wake IRQ stuff I mentioned?
> In the path you're talking about it just checks
> device_awake_path(dev) && genpd_is_active_wakeup(genpd)
> However if the device irq is just marked as a wake IRQ, I don't think
> that is checked anywhere in this path. So definitely if the IRQ of your
> device is set as a wake IRQ, it will still get suspended and resumed as
> usual and that's what you want right?

The missing piece for the wake_irq, is to know whether the interrupt
can be delivered via an out-band-powered-on-logic, thus without
requiring the device to stay powered-on during system suspend.

[...]

Kind regards
Uffe
Re: [PATCH v3 1/4] pmdomain: core: Introduce device_set/get_out_band_wakeup()
Posted by Dhruva Gole 2 weeks, 1 day ago
On Sep 02, 2025 at 11:33:00 +0800, Peng Fan wrote:
> For some cases, a device could still wakeup the system even if its power
> domain is in off state, because the device's wakeup hardware logic is
> in an always-on domain.

Don't we already have something like wake IRQs [1] for such purposes?

8<----------------------------------------------------------------------
That may involve turning on a special signal handling logic within the
platform (such as an SoC) so that signals from a given line are routed
in a different way during system sleep so as to trigger a system wakeup
when needed
----------------------------------------------------------------------->8

[1] https://docs.kernel.org/power/suspend-and-interrupts.html#system-wakeup-interrupts-enable-irq-wake-and-disable-irq-wake

> 
> To support this case, introduce device_set/get_out_band_wakeup() to
> allow device drivers to control the behaviour in genpd for a device
> that is attached to it.

Do you have any explanation as to why wake IRQ is not solving this
problem and you need to introduce these new APIs?

> 
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
> ---
>  drivers/pmdomain/core.c   |  6 ++++--
>  include/linux/pm.h        |  1 +
>  include/linux/pm_wakeup.h | 17 +++++++++++++++++
>  3 files changed, 22 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
> index 0006ab3d078972cc72a6dd22a2144fb31443e3da..8e37758cea88a9ee051ad9fb13bdd3feb4f8745e 100644
> --- a/drivers/pmdomain/core.c
> +++ b/drivers/pmdomain/core.c
> @@ -1549,7 +1549,8 @@ static int genpd_finish_suspend(struct device *dev,
>  	if (ret)
>  		return ret;
>  
> -	if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
> +	if (device_awake_path(dev) && genpd_is_active_wakeup(genpd) &&
> +	    !device_get_out_band_wakeup(dev))
>  		return 0;
>  
>  	if (genpd->dev_ops.stop && genpd->dev_ops.start &&
> @@ -1604,7 +1605,8 @@ static int genpd_finish_resume(struct device *dev,
>  	if (IS_ERR(genpd))
>  		return -EINVAL;
>  
> -	if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
> +	if (device_awake_path(dev) && genpd_is_active_wakeup(genpd) &&
> +	    !device_get_out_band_wakeup(dev))
>  		return resume_noirq(dev);
>  
>  	genpd_lock(genpd);
> diff --git a/include/linux/pm.h b/include/linux/pm.h
> index cc7b2dc28574c24ece2f651352d4d23ecaf15f31..5b28a4f2e87e2aa34acc709e146ce729acace344 100644
> --- a/include/linux/pm.h
> +++ b/include/linux/pm.h
> @@ -684,6 +684,7 @@ struct dev_pm_info {
>  	bool			smart_suspend:1;	/* Owned by the PM core */
>  	bool			must_resume:1;		/* Owned by the PM core */
>  	bool			may_skip_resume:1;	/* Set by subsystems */
> +	bool			out_band_wakeup:1;
>  	bool			strict_midlayer:1;
>  #else
>  	bool			should_wakeup:1;
> diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
> index c838b4a30f876ef5a66972d16f461cfba9ff2814..c461c7edef6f7927d696b7d18b59a6a1147f53a3 100644
> --- a/include/linux/pm_wakeup.h
> +++ b/include/linux/pm_wakeup.h
> @@ -94,6 +94,16 @@ static inline void device_set_wakeup_path(struct device *dev)
>  	dev->power.wakeup_path = true;
>  }
>  
> +static inline void device_set_out_band_wakeup(struct device *dev, bool capable)
> +{
> +	dev->power.out_band_wakeup = capable;
> +}
> +
> +static inline bool device_get_out_band_wakeup(struct device *dev)
> +{
> +	return dev->power.out_band_wakeup;
> +}
> +
>  /* drivers/base/power/wakeup.c */
>  extern struct wakeup_source *wakeup_source_register(struct device *dev,
>  						    const char *name);
> @@ -162,6 +172,13 @@ static inline bool device_wakeup_path(struct device *dev)
>  
>  static inline void device_set_wakeup_path(struct device *dev) {}
>  
> +static inline void device_set_out_band_wakeup(struct device *dev, bool capable) {}
> +
> +static inline bool device_get_out_band_wakeup(struct device *dev)
> +{
> +	return false;
> +}
> +
>  static inline void __pm_stay_awake(struct wakeup_source *ws) {}

-- 
Best regards,
Dhruva Gole
Texas Instruments Incorporated
Re: [PATCH v3 1/4] pmdomain: core: Introduce device_set/get_out_band_wakeup()
Posted by Xu Yang 1 month ago
On Tue, Sep 02, 2025 at 11:33:00AM +0800, Peng Fan wrote:
> For some cases, a device could still wakeup the system even if its power
> domain is in off state, because the device's wakeup hardware logic is
> in an always-on domain.
> 
> To support this case, introduce device_set/get_out_band_wakeup() to
> allow device drivers to control the behaviour in genpd for a device
> that is attached to it.
> 
> Signed-off-by: Peng Fan <peng.fan@nxp.com>

Tested-by: Xu Yang <xu.yang_2@nxp.com>

> ---
>  drivers/pmdomain/core.c   |  6 ++++--
>  include/linux/pm.h        |  1 +
>  include/linux/pm_wakeup.h | 17 +++++++++++++++++
>  3 files changed, 22 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
> index 0006ab3d078972cc72a6dd22a2144fb31443e3da..8e37758cea88a9ee051ad9fb13bdd3feb4f8745e 100644
> --- a/drivers/pmdomain/core.c
> +++ b/drivers/pmdomain/core.c
> @@ -1549,7 +1549,8 @@ static int genpd_finish_suspend(struct device *dev,
>  	if (ret)
>  		return ret;
>  
> -	if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
> +	if (device_awake_path(dev) && genpd_is_active_wakeup(genpd) &&
> +	    !device_get_out_band_wakeup(dev))
>  		return 0;
>  
>  	if (genpd->dev_ops.stop && genpd->dev_ops.start &&
> @@ -1604,7 +1605,8 @@ static int genpd_finish_resume(struct device *dev,
>  	if (IS_ERR(genpd))
>  		return -EINVAL;
>  
> -	if (device_awake_path(dev) && genpd_is_active_wakeup(genpd))
> +	if (device_awake_path(dev) && genpd_is_active_wakeup(genpd) &&
> +	    !device_get_out_band_wakeup(dev))
>  		return resume_noirq(dev);
>  
>  	genpd_lock(genpd);
> diff --git a/include/linux/pm.h b/include/linux/pm.h
> index cc7b2dc28574c24ece2f651352d4d23ecaf15f31..5b28a4f2e87e2aa34acc709e146ce729acace344 100644
> --- a/include/linux/pm.h
> +++ b/include/linux/pm.h
> @@ -684,6 +684,7 @@ struct dev_pm_info {
>  	bool			smart_suspend:1;	/* Owned by the PM core */
>  	bool			must_resume:1;		/* Owned by the PM core */
>  	bool			may_skip_resume:1;	/* Set by subsystems */
> +	bool			out_band_wakeup:1;
>  	bool			strict_midlayer:1;
>  #else
>  	bool			should_wakeup:1;
> diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
> index c838b4a30f876ef5a66972d16f461cfba9ff2814..c461c7edef6f7927d696b7d18b59a6a1147f53a3 100644
> --- a/include/linux/pm_wakeup.h
> +++ b/include/linux/pm_wakeup.h
> @@ -94,6 +94,16 @@ static inline void device_set_wakeup_path(struct device *dev)
>  	dev->power.wakeup_path = true;
>  }
>  
> +static inline void device_set_out_band_wakeup(struct device *dev, bool capable)
> +{
> +	dev->power.out_band_wakeup = capable;
> +}
> +
> +static inline bool device_get_out_band_wakeup(struct device *dev)
> +{
> +	return dev->power.out_band_wakeup;
> +}
> +
>  /* drivers/base/power/wakeup.c */
>  extern struct wakeup_source *wakeup_source_register(struct device *dev,
>  						    const char *name);
> @@ -162,6 +172,13 @@ static inline bool device_wakeup_path(struct device *dev)
>  
>  static inline void device_set_wakeup_path(struct device *dev) {}
>  
> +static inline void device_set_out_band_wakeup(struct device *dev, bool capable) {}
> +
> +static inline bool device_get_out_band_wakeup(struct device *dev)
> +{
> +	return false;
> +}
> +
>  static inline void __pm_stay_awake(struct wakeup_source *ws) {}
>  
>  static inline void pm_stay_awake(struct device *dev) {}
> 
> -- 
> 2.37.1
>