Re: [PATCH] PM / wakeup: Enable option to specify wakeup as a non in-band wakeup

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tuesday, January 9, 2018 11:54:11 AM CET Ulf Hansson wrote:
> In some cases, a driver may not require its device to be powered on to be
> able to deliver wakeup signals during system suspend.

That quite often is the case.

It is the standard way wakeup signaling works in PCI and in ACPI.

> Likely the most common scenario when this is the case, is a driver routing
> the wakeup signal through a GPIO IRQ, instead of using the regular in-band
> IRQ logic, via the device itself.
> 
> Obviously the driver may put its device into a low power state during
> system suspend in cases like this. For example it may gate clocks, put
> pinctrls into sleep state, etc.
> 
> However, for middle-layers and PM domains (like genpd), which checks the
> return value from device_may_wakeup() and/or the ->dev.power.wakeup_path
> status flag, there is information missing about scenarios like these.
> 
> In the case of genpd, when it finds the ->dev.power.wakeup_path status flag
> being set for a device during system suspend, it leaves the device in
> powered on state including its PM domain. In other words, wasting power.
> 
> To address this issue, add a new ->dev.power.no_inband_wakeup flag for the
> device, which drivers may set/clear to inform the PM core, in case
> device_may_wakeup() returns true, whether that shall make the
> ->dev.power.wakeup_path status flag to be set or not for the device.
> 
> The PM core checks the ->dev.power.no_inband_wakeup flag in the
> __device_suspend() phase, after invoking the ->suspend() callback for the
> device. At that point, the driver is responsible that it has set a correct
> value to the flag.
> 
> Let's also introduce a helper function, device_set_no_inband_wakeup(),
> which drivers shall use to set/clear the ->dev.power.no_inband_wakeup flag.

Wait, wait.

> Signed-off-by: Ulf Hansson <ulf.hansson@xxxxxxxxxx>
> ---
> 
> To get some additional background, one may look at earlier discussions from
> various threads. The most recent is in and RFD [1] from Rafael and from an mmc
> series by Adrian [2].

Let's first conclude that discussion, please.

> [1]
> https://marc.info/?l=linux-pm&m=151541229425689&w=2
> 
> [2]
> https://www.spinics.net/lists/linux-mmc/msg47549.html
> 
> ---
>  drivers/base/power/main.c | 2 +-
>  include/linux/pm.h        | 1 +
>  include/linux/pm_wakeup.h | 8 ++++++++
>  3 files changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
> index 02a497e..376c275 100644
> --- a/drivers/base/power/main.c
> +++ b/drivers/base/power/main.c
> @@ -1794,7 +1794,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
>   End:
>  	if (!error) {
>  		dev->power.is_suspended = true;
> -		if (device_may_wakeup(dev))
> +		if (device_may_wakeup(dev) && !dev->power.no_inband_wakeup)

That is not just a system-wide PM concept.  It affects runtime PM potentially
too.

>  			dev->power.wakeup_path = true;
>  
>  		dpm_propagate_wakeup_to_parent(dev);
> diff --git a/include/linux/pm.h b/include/linux/pm.h
> index e723b78..d131834 100644
> --- a/include/linux/pm.h
> +++ b/include/linux/pm.h
> @@ -600,6 +600,7 @@ struct dev_pm_info {
>  	struct completion	completion;
>  	struct wakeup_source	*wakeup;
>  	bool			wakeup_path:1;
> +	bool			no_inband_wakeup:1;
>  	bool			syscore:1;
>  	bool			no_pm_callbacks:1;	/* Owned by the PM core */
>  	unsigned int		must_resume:1;	/* Owned by the PM core */
> diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
> index 4238dde..5d40887 100644
> --- a/include/linux/pm_wakeup.h
> +++ b/include/linux/pm_wakeup.h
> @@ -93,6 +93,11 @@ static inline void device_set_wakeup_path(struct device *dev)
>  	dev->power.wakeup_path = true;
>  }
>  
> +static inline void device_set_no_inband_wakeup(struct device *dev, bool wakeup)
> +{
> +	dev->power.no_inband_wakeup = wakeup;
> +}
> +
>  /* drivers/base/power/wakeup.c */
>  extern void wakeup_source_prepare(struct wakeup_source *ws, const char *name);
>  extern struct wakeup_source *wakeup_source_create(const char *name);
> @@ -181,6 +186,9 @@ static inline bool device_may_wakeup(struct device *dev)
>  
>  static inline void device_set_wakeup_path(struct device *dev) {}
>  
> +static inline void device_set_no_inband_wakeup(struct device *dev,
> +					       bool wakeup) {}
> +
>  static inline void __pm_stay_awake(struct wakeup_source *ws) {}
>  
>  static inline void pm_stay_awake(struct device *dev) {}
> 





[Index of Archives]     [Linux Samsung SOC]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux