From: Rafael J. Wysocki <hidden> Date: 2012-10-29 09:10:37
Hi All,
The following series of patches rearranges ACPI device power management
code and introduces universal PM callback routines that may be used by
bus types that don't support power management natively and/or by drivers
of devices with those bus types.
[1/7] Move routines for adding/removing device wakeup notifiers into a separate
file.
[2/7] Move device power state selection routine to the new device PM file.
[3/7] Move runtime remote wakeup setup routine to the new device PM file.
[4/7] Split device wakeup management routines, so that it is possible to
reduce the number of acpi_bus_get_device() calls.
[5/7] Provide low-lever device PM functions operationg on struct acpi_device
objects.
[6/7] Move device PM functions related to sleep states from sleep.c to the
new device PM file.
[7/7] Provide ACPI PM callback routines for subsystems.
The patches are on top of the current Linus' tree with the git branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git pm-qos
merged. The resulting kernel has been run on my test-bed Toshiba Portege R500
and hasn't crashed it, but more testing is still needed, so please use it with
care.
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
From: Rafael J. Wysocki <hidden> Date: 2012-10-29 09:10:19
From: Rafael J. Wysocki <redacted>
Some bus types don't support power management natively, but generally
there may be device nodes in ACPI tables corresponding to the devices
whose bus types they are (under ACPI 5 those bus types may be SPI,
I2C and platform). If that is the case, standard ACPI power
management may be applied to those devices, although currently the
kernel has no means for that.
For this reason, provide a set of routines that may be used as power
management callbacks for such devices. This may be done in three
different ways.
(1) Device drivers handling the devices in question may run
acpi_dev_pm_attach() in their .probe() routines, which (on
success) will cause the devices to be added to the general ACPI
PM domain and ACPI power management will be used for them going
forward. Then, acpi_dev_pm_detach() may be used to remove the
devices from the general ACPI PM domain if ACPI power management
is not necessary for them any more.
(2) The devices' subsystems may use acpi_subsys_runtime_suspend(),
acpi_subsys_runtime_resume(), acpi_subsys_prepare(),
acpi_subsys_suspend_late(), acpi_subsys_resume_early() as their
power management callbacks in the same way as the general ACPI
PM domain does that.
(3) The devices' drivers may execute acpi_dev_suspend_late(),
acpi_dev_resume_early(), acpi_dev_runtime_suspend(),
acpi_dev_runtime_resume() from their power management callbacks
as appropriate, if that's absolutely necessary, but it is not
recommended to do that, because such drivers may not work
without ACPI support as a result.
Signed-off-by: Rafael J. Wysocki <redacted>
---
drivers/acpi/device_pm.c | 314 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 34 +++++
2 files changed, 348 insertions(+)
Index: linux/drivers/acpi/device_pm.c
===================================================================
From: Rafael J. Wysocki <hidden> Date: 2012-10-29 09:10:22
From: Rafael J. Wysocki <redacted>
Introduce helper function returning the target sleep state of the
system and use it to move the remaining device power management
functions from sleep.c to device_pm.c.
Signed-off-by: Rafael J. Wysocki <redacted>
---
drivers/acpi/device_pm.c | 54 ++++++++++++++++++++++++++++++++++++++++
drivers/acpi/sleep.c | 63 ++++-------------------------------------------
include/acpi/acpi_bus.h | 1
3 files changed, 61 insertions(+), 57 deletions(-)
Index: linux/drivers/acpi/sleep.c
===================================================================
@@ -80,6 +80,12 @@ static int acpi_sleep_prepare(u32 acpi_s#ifdef CONFIG_ACPI_SLEEPstaticu32acpi_target_sleep_state=ACPI_STATE_S0;++u32acpi_target_system_state(void)+{+returnacpi_target_sleep_state;+}+staticboolpwr_btn_event_pending;/*
@@ -695,63 +701,6 @@ int acpi_suspend(u32 acpi_state)return-EINVAL;}-#ifdef CONFIG_PM-/**-*acpi_pm_device_sleep_state-GetpreferredpowerstateofACPIdevice.-*@dev:Devicewhosepreferredtargetpowerstatetoreturn.-*@d_min_p:Locationtostoretheupperlimitoftheallowedstatesrange.-*@d_max_in:Deepestlow-powerstatetotakeintoconsideration.-*Returnvalue:Preferredpowerstateofthedeviceonsuccess,-ENODEV-*(ifthere'sno'structacpi_device'for@dev)or-EINVALonfailure-*-*Thecallermustensurethat@devisvalidbeforeusingthisfunction.-*/-intacpi_pm_device_sleep_state(structdevice*dev,int*d_min_p,intd_max_in)-{-acpi_handlehandle=DEVICE_ACPI_HANDLE(dev);-structacpi_device*adev;--if(!handle||ACPI_FAILURE(acpi_bus_get_device(handle,&adev))){-dev_dbg(dev,"ACPI handle without context in %s!\n",__func__);-return-ENODEV;-}--returnacpi_device_power_state(dev,adev,acpi_target_sleep_state,-d_max_in,d_min_p);-}-EXPORT_SYMBOL(acpi_pm_device_sleep_state);-#endif /* CONFIG_PM */--#ifdef CONFIG_PM_SLEEP-/**-*acpi_pm_device_sleep_wake-Enableordisabledevicetowakeupthesystem.-*@dev:Devicetoenable/desibletowakeupthesystemfromsleepstates.-*@enable:Whethertoenableordisable@devtowakeupthesystem.-*/-intacpi_pm_device_sleep_wake(structdevice*dev,boolenable)-{-acpi_handlehandle;-structacpi_device*adev;-interror;--if(!device_can_wakeup(dev))-return-EINVAL;--handle=DEVICE_ACPI_HANDLE(dev);-if(!handle||ACPI_FAILURE(acpi_bus_get_device(handle,&adev))){-dev_dbg(dev,"ACPI handle without context in %s!\n",__func__);-return-ENODEV;-}--error=__acpi_device_sleep_wake(adev,acpi_target_sleep_state,enable);-if(!error)-dev_info(dev,"System wakeup %s by ACPI\n",-enable?"enabled":"disabled");--returnerror;-}-#endif /* CONFIG_PM_SLEEP */-staticvoidacpi_power_off_prepare(void){/* Prepare to power off the system */
@@ -198,6 +198,31 @@ int acpi_device_power_state(struct devic}EXPORT_SYMBOL_GPL(acpi_device_power_state);+/**+*acpi_pm_device_sleep_state-GetpreferredpowerstateofACPIdevice.+*@dev:Devicewhosepreferredtargetpowerstatetoreturn.+*@d_min_p:Locationtostoretheupperlimitoftheallowedstatesrange.+*@d_max_in:Deepestlow-powerstatetotakeintoconsideration.+*Returnvalue:Preferredpowerstateofthedeviceonsuccess,-ENODEV+*(ifthere'sno'structacpi_device'for@dev)or-EINVALonfailure+*+*Thecallermustensurethat@devisvalidbeforeusingthisfunction.+*/+intacpi_pm_device_sleep_state(structdevice*dev,int*d_min_p,intd_max_in)+{+acpi_handlehandle=DEVICE_ACPI_HANDLE(dev);+structacpi_device*adev;++if(!handle||ACPI_FAILURE(acpi_bus_get_device(handle,&adev))){+dev_dbg(dev,"ACPI handle without context in %s!\n",__func__);+return-ENODEV;+}++returnacpi_device_power_state(dev,adev,acpi_target_system_state(),+d_max_in,d_min_p);+}+EXPORT_SYMBOL(acpi_pm_device_sleep_state);+#ifdef CONFIG_PM_RUNTIME/***__acpi_device_run_wake-Enable/disableruntimeremotewakeupfordevice.
@@ -274,4 +299,33 @@ int __acpi_device_sleep_wake(struct acpiacpi_enable_wakeup_device_power(adev,target_state):acpi_disable_wakeup_device_power(adev);}++/**+*acpi_pm_device_sleep_wake-Enableordisabledevicetowakeupthesystem.+*@dev:Devicetoenable/desibletowakeupthesystemfromsleepstates.+*@enable:Whethertoenableordisable@devtowakeupthesystem.+*/+intacpi_pm_device_sleep_wake(structdevice*dev,boolenable)+{+acpi_handlehandle;+structacpi_device*adev;+interror;++if(!device_can_wakeup(dev))+return-EINVAL;++handle=DEVICE_ACPI_HANDLE(dev);+if(!handle||ACPI_FAILURE(acpi_bus_get_device(handle,&adev))){+dev_dbg(dev,"ACPI handle without context in %s!\n",__func__);+return-ENODEV;+}++error=__acpi_device_sleep_wake(adev,acpi_target_system_state(),+enable);+if(!error)+dev_info(dev,"System wakeup %s by ACPI\n",+enable?"enabled":"disabled");++returnerror;+}#endif /* CONFIG_PM_SLEEP */
From: Rafael J. Wysocki <hidden> Date: 2012-10-29 09:10:24
From: Rafael J. Wysocki <redacted>
If the caller of acpi_bus_set_power() already has a pointer to the
struct acpi_device object corresponding to the device in question, it
doesn't make sense for it to go through acpi_bus_get_device(), which
may be costly, because it involves acquiring the global ACPI
namespace mutex.
For this reason, export the function operating on struct acpi_device
objects used internally by acpi_bus_set_power(), so that it may be
called instead of acpi_bus_set_power() in the above case, and change
its name to acpi_device_set_power().
Additionally, introduce two inline wrappers for checking ACPI PM
capabilities of devices represented by struct acpi_device objects.
Signed-off-by: Rafael J. Wysocki <redacted>
---
drivers/acpi/bus.c | 15 ++++++++++++---
include/acpi/acpi_bus.h | 11 +++++++++++
2 files changed, 23 insertions(+), 3 deletions(-)
Index: linux/drivers/acpi/bus.c
===================================================================
From: Rafael J. Wysocki <hidden> Date: 2012-10-29 09:10:39
From: Rafael J. Wysocki <redacted>
ACPI routines for adding and removing device wakeup notifiers are
currently defined in a PCI-specific file, but they will be necessary
for non-PCI devices too, so move them to a separate file under
drivers/acpi and rename them to indicate their ACPI origins.
Signed-off-by: Rafael J. Wysocki <redacted>
---
drivers/acpi/Makefile | 3 +
drivers/acpi/device_pm.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/pci/pci-acpi.c | 71 ++----------------------------------
include/acpi/acpi_bus.h | 15 +++++++
4 files changed, 112 insertions(+), 68 deletions(-)
Index: linux/drivers/acpi/device_pm.c
===================================================================
@@ -21,9 +21,10 @@ obj-y += acpi.o \acpi-y+=osl.outils.oreboot.oacpi-y+=nvs.o-# sleep related files+# Power management related filesacpi-y+=wakeup.oacpi-y+=sleep.o+acpi-$(CONFIG_PM)+=device_pm.oacpi-$(CONFIG_ACPI_SLEEP)+=proc.o
From: Rafael J. Wysocki <hidden> Date: 2012-10-29 09:10:40
From: Rafael J. Wysocki <redacted>
The ACPI function for choosing device power state is now located
in drivers/acpi/sleep.c, but drivers/acpi/device_pm.c is a more
logical place for it, so move it there.
However, instead of moving the function entirely, move its core only
under a different name and with a different list of arguments, so
that it is more flexible, and leave a wrapper around it in the
original location.
Signed-off-by: Rafael J. Wysocki <redacted>
---
drivers/acpi/device_pm.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/sleep.c | 88 +-------------------------------------
include/acpi/acpi_bus.h | 15 ++++++
3 files changed, 124 insertions(+), 86 deletions(-)
Index: linux/drivers/acpi/device_pm.c
===================================================================
@@ -89,3 +91,108 @@ acpi_status acpi_remove_pm_notifier(strumutex_unlock(&acpi_pm_notifier_lock);returnstatus;}++/**+*acpi_device_power_state-GetpreferredpowerstateofACPIdevice.+*@dev:Devicewhosepreferredtargetpowerstatetoreturn.+*@adev:ACPIdevicenodecorrespondingto@dev.+*@target_state:Systemstatetomatchtheresultantdevicestate.+*@d_max_in:Deepestlow-powerstatetotakeintoconsideration.+*@d_min_p:Locationtostoretheupperlimitoftheallowedstatesrange.+*Returnvalue:Preferredpowerstateofthedeviceonsuccess,-ENODEV+*(ifthere'sno'structacpi_device'for@dev)or-EINVALonfailure+*+*Findthelowestpower(highestnumber)ACPIdevicepowerstatethatthe+*devicecanbeinwhilethesystemisinthestaterepresentedby+*@target_state.If@d_min_pisset,thehighestpower(lowestnumber)device+*powerstatethat@devcanbeinforthegivensystemsleepstateisstored+*atthelocationpointedtobyit.+*+*Callersmustensurethat@devand@adevarevalidpointersandthat@adev+*actuallycorrespondsto@devbeforeusingthisfunction.+*/+intacpi_device_power_state(structdevice*dev,structacpi_device*adev,+u32target_state,intd_max_in,int*d_min_p)+{+characpi_method[]="_SxD";+unsignedlonglongd_min,d_max;+boolwakeup=false;++if(d_max_in<ACPI_STATE_D0||d_max_in>ACPI_STATE_D3)+return-EINVAL;++if(d_max_in>ACPI_STATE_D3_HOT){+enumpm_qos_flags_statusstat;++stat=dev_pm_qos_flags(dev,PM_QOS_FLAG_NO_POWER_OFF);+if(stat==PM_QOS_FLAGS_ALL)+d_max_in=ACPI_STATE_D3_HOT;+}++acpi_method[2]='0'+target_state;+/*+*IfthesleepstateisS0,thelowestlimitfromACPIisD3,+*butifthedevicehas_S0W,wewillusethevaluefrom_S0W+*asthelowestlimitfromACPI.Finally,wewillconstrain+*thelowestlimitwiththespecifiedone.+*/+d_min=ACPI_STATE_D0;+d_max=ACPI_STATE_D3;++/*+*Ifpresent,_SxDmethodsreturntheminimumD-state(highestpower+*state)wecanuseforthecorrespondingS-states.Otherwise,the+*minimumD-stateisD0(ACPI3.x).+*+*NOTE:Werelyonacpi_evaluate_integer()notclobberingtheinteger+*provided--that'sourfaultrecovery,weignoreretval.+*/+if(target_state>ACPI_STATE_S0){+acpi_evaluate_integer(adev->handle,acpi_method,NULL,&d_min);+wakeup=device_may_wakeup(dev)&&adev->wakeup.flags.valid+&&adev->wakeup.sleep_state>=target_state;+}elseif(dev_pm_qos_flags(dev,PM_QOS_FLAG_REMOTE_WAKEUP)!=+PM_QOS_FLAGS_NONE){+wakeup=adev->wakeup.flags.valid;+}++/*+*If_PRWsayswecanwakeupthesystemfromthetargetsleepstate,+*theD-statereturnedby_SxDissufficientforthat(weassumea+*wakeup-awaredriverifwakeisset).Still,if_SxWexists+*(ACPI3.x),itshouldreturnthemaximum(lowestpower)D-statethat+*canwakethesystem._S0Wmaybevalid,too.+*/+if(wakeup){+acpi_statusstatus;++acpi_method[3]='W';+status=acpi_evaluate_integer(adev->handle,acpi_method,NULL,+&d_max);+if(ACPI_FAILURE(status)){+if(target_state!=ACPI_STATE_S0||+status!=AE_NOT_FOUND)+d_max=d_min;+}elseif(d_max<d_min){+/* Warn the user of the broken DSDT */+printk(KERN_WARNING"ACPI: Wrong value from %s\n",+acpi_method);+/* Sanitize it */+d_min=d_max;+}+}++if(d_max_in<d_min)+return-EINVAL;+if(d_min_p)+*d_min_p=d_min;+/* constrain d_max with specified lowest limit (max number) */+if(d_max>d_max_in){+for(d_max=d_max_in;d_max>d_min;d_max--){+if(adev->power.states[d_max].flags.valid)+break;+}+}+returnd_max;+}+EXPORT_SYMBOL_GPL(acpi_device_power_state);
@@ -706,101 +705,20 @@ int acpi_suspend(u32 acpi_state)*Returnvalue:Preferredpowerstateofthedeviceonsuccess,-ENODEV*(ifthere'sno'structacpi_device'for@dev)or-EINVALonfailure*-*Findthelowestpower(highestnumber)ACPIdevicepowerstatethatthe-*devicecanbeinwhilethesystemisinthesleepstaterepresented-*by%acpi_target_sleep_state.If@d_min_pisset,thehighestpower(lowest-*number)devicepowerstatethat@devcanbeinforthegivensystemsleep-*stateisstoredatthelocationpointedtobyit.-**Thecallermustensurethat@devisvalidbeforeusingthisfunction.*/intacpi_pm_device_sleep_state(structdevice*dev,int*d_min_p,intd_max_in){acpi_handlehandle=DEVICE_ACPI_HANDLE(dev);structacpi_device*adev;-characpi_method[]="_SxD";-unsignedlonglongd_min,d_max;-boolwakeup=false;-if(d_max_in<ACPI_STATE_D0||d_max_in>ACPI_STATE_D3)-return-EINVAL;if(!handle||ACPI_FAILURE(acpi_bus_get_device(handle,&adev))){-printk(KERN_DEBUG"ACPI handle has no context!\n");+dev_dbg(dev,"ACPI handle without context in %s!\n",__func__);return-ENODEV;}-if(d_max_in>ACPI_STATE_D3_HOT){-enumpm_qos_flags_statusstat;--stat=dev_pm_qos_flags(dev,PM_QOS_FLAG_NO_POWER_OFF);-if(stat==PM_QOS_FLAGS_ALL)-d_max_in=ACPI_STATE_D3_HOT;-}--acpi_method[2]='0'+acpi_target_sleep_state;-/*-*IfthesleepstateisS0,thelowestlimitfromACPIisD3,-*butifthedevicehas_S0W,wewillusethevaluefrom_S0W-*asthelowestlimitfromACPI.Finally,wewillconstrain-*thelowestlimitwiththespecifiedone.-*/-d_min=ACPI_STATE_D0;-d_max=ACPI_STATE_D3;-/*-*Ifpresent,_SxDmethodsreturntheminimumD-state(highestpower-*state)wecanuseforthecorrespondingS-states.Otherwise,the-*minimumD-stateisD0(ACPI3.x).-*-*NOTE:Werelyonacpi_evaluate_integer()notclobberingtheinteger-*provided--that'sourfaultrecovery,weignoreretval.-*/-if(acpi_target_sleep_state>ACPI_STATE_S0){-acpi_evaluate_integer(handle,acpi_method,NULL,&d_min);-wakeup=device_may_wakeup(dev)&&adev->wakeup.flags.valid-&&adev->wakeup.sleep_state>=acpi_target_sleep_state;-}elseif(dev_pm_qos_flags(dev,PM_QOS_FLAG_REMOTE_WAKEUP)!=-PM_QOS_FLAGS_NONE){-wakeup=adev->wakeup.flags.valid;-}--/*-*If_PRWsayswecanwakeupthesystemfromthetargetsleepstate,-*theD-statereturnedby_SxDissufficientforthat(weassumea-*wakeup-awaredriverifwakeisset).Still,if_SxWexists-*(ACPI3.x),itshouldreturnthemaximum(lowestpower)D-statethat-*canwakethesystem._S0Wmaybevalid,too.-*/-if(wakeup){-acpi_statusstatus;--acpi_method[3]='W';-status=acpi_evaluate_integer(handle,acpi_method,NULL,-&d_max);-if(ACPI_FAILURE(status)){-if(acpi_target_sleep_state!=ACPI_STATE_S0||-status!=AE_NOT_FOUND)-d_max=d_min;-}elseif(d_max<d_min){-/* Warn the user of the broken DSDT */-printk(KERN_WARNING"ACPI: Wrong value from %s\n",-acpi_method);-/* Sanitize it */-d_min=d_max;-}-}--if(d_max_in<d_min)-return-EINVAL;-if(d_min_p)-*d_min_p=d_min;-/* constrain d_max with specified lowest limit (max number) */-if(d_max>d_max_in){-for(d_max=d_max_in;d_max>d_min;d_max--){-if(adev->power.states[d_max].flags.valid)-break;-}-}-returnd_max;+returnacpi_device_power_state(dev,adev,acpi_target_sleep_state,+d_max_in,d_min_p);}EXPORT_SYMBOL(acpi_pm_device_sleep_state);#endif /* CONFIG_PM */
From: Rafael J. Wysocki <hidden> Date: 2012-10-29 09:11:47
From: Rafael J. Wysocki <redacted>
The ACPI function for setting up devices to do runtime remote
wakeup is now located in drivers/acpi/sleep.c, but
drivers/acpi/device_pm.c is a more logical place for it, so move it
there.
No functional changes should result from this modification.
Signed-off-by: Rafael J. Wysocki <redacted>
---
drivers/acpi/device_pm.c | 39 +++++++++++++++++++++++++++++++++++++++
drivers/acpi/sleep.c | 39 ---------------------------------------
2 files changed, 39 insertions(+), 39 deletions(-)
Index: linux/drivers/acpi/device_pm.c
===================================================================
@@ -196,3 +197,41 @@ int acpi_device_power_state(struct devicreturnd_max;}EXPORT_SYMBOL_GPL(acpi_device_power_state);++#ifdef CONFIG_PM_RUNTIME+/**+*acpi_pm_device_run_wake-Enable/disableremotewakeupforgivendevice.+*@phys_dev:Devicetoenable/disabletheplatformtowakeup.+*@enable:Whethertoenableordisablethewakeupfunctionality.+*+*FindtheACPIdeviceobjectcorrespondingto@phys_devandtryto+*enable/disabletheGPEassociatedwithit,sothatitcangenerate+*wakeupsignalsforthedeviceinresponsetoexternal(remote)events.+*/+intacpi_pm_device_run_wake(structdevice*phys_dev,boolenable)+{+structacpi_device*dev;+acpi_handlehandle;++if(!device_run_wake(phys_dev))+return-EINVAL;++handle=DEVICE_ACPI_HANDLE(phys_dev);+if(!handle||ACPI_FAILURE(acpi_bus_get_device(handle,&dev))){+dev_dbg(phys_dev,"ACPI handle has no context in %s!\n",+__func__);+return-ENODEV;+}++if(enable){+acpi_enable_wakeup_device_power(dev,ACPI_STATE_S0);+acpi_enable_gpe(dev->wakeup.gpe_device,dev->wakeup.gpe_number);+}else{+acpi_disable_gpe(dev->wakeup.gpe_device,dev->wakeup.gpe_number);+acpi_disable_wakeup_device_power(dev);+}++return0;+}+EXPORT_SYMBOL(acpi_pm_device_run_wake);+#endif /* CONFIG_PM_RUNTIME */
From: Rafael J. Wysocki <hidden> Date: 2012-10-29 09:12:09
From: Rafael J. Wysocki <redacted>
Two device wakeup management routines in device_pm.c and sleep.c,
acpi_pm_device_run_wake() and acpi_pm_device_sleep_wake(), take a
device pointer argument and use it to obtain the ACPI handle of the
corresponding ACPI namespace node. That handle is then used to get
the address of the struct acpi_device object corresponding to the
struct device passed as the argument.
Unfortunately, that last operation may be costly, because it involves
taking the global ACPI namespace mutex, so it shouldn't be carried
out too often. However, the callers of those routines usually call
them in a row with acpi_pm_device_sleep_state() which also takes that
mutex for the same reason, so it would be more efficient if they ran
acpi_bus_get_device() themselves to obtain a pointer to the struct
acpi_device object in question and then passed that pointer to the
appropriate PM routines.
To make that possible, split each of the PM routines mentioned above
in two parts, one taking a struct acpi_device pointer argument and
the other implementing the current interface for compatibility.
Additionally, change acpi_pm_device_run_wake() to actually return
an error code if there is an error while setting up runtime remote
wakeup for the device.
Signed-off-by: Rafael J. Wysocki <redacted>
---
drivers/acpi/device_pm.c | 74 ++++++++++++++++++++++++++++++++++++-----------
drivers/acpi/sleep.c | 8 +----
include/acpi/acpi_bus.h | 11 ++++++
3 files changed, 71 insertions(+), 22 deletions(-)
Index: linux/drivers/acpi/device_pm.c
===================================================================
@@ -200,38 +200,78 @@ EXPORT_SYMBOL_GPL(acpi_device_power_stat#ifdef CONFIG_PM_RUNTIME/**-*acpi_pm_device_run_wake-Enable/disableremotewakeupforgivendevice.-*@phys_dev:Devicetoenable/disabletheplatformtowakeup.+*__acpi_device_run_wake-Enable/disableruntimeremotewakeupfordevice.+*@adev:ACPIdevicetoenable/disabletheremotewakeupfor.*@enable:Whethertoenableordisablethewakeupfunctionality.*-*FindtheACPIdeviceobjectcorrespondingto@phys_devandtryto-*enable/disabletheGPEassociatedwithit,sothatitcangenerate-*wakeupsignalsforthedeviceinresponsetoexternal(remote)events.+*Enable/disabletheGPEassociatedwith@adevsothatitcangenerate+*wakeupsignalsforthedeviceinresponsetoexternal(remote)eventsand+*enable/disabledevicewakeuppower.+*+*Callersmustensurethat@adevisavalidACPIdevicenodebeforeexecuting+*thisfunction.+*/+int__acpi_device_run_wake(structacpi_device*adev,boolenable)+{+structacpi_device_wakeup*wakeup=&adev->wakeup;++if(enable){+acpi_statusres;+interror;++error=acpi_enable_wakeup_device_power(adev,ACPI_STATE_S0);+if(error)+returnerror;++res=acpi_enable_gpe(wakeup->gpe_device,wakeup->gpe_number);+if(ACPI_FAILURE(res)){+acpi_disable_wakeup_device_power(adev);+return-EIO;+}+}else{+acpi_disable_gpe(wakeup->gpe_device,wakeup->gpe_number);+acpi_disable_wakeup_device_power(adev);+}+return0;+}++/**+*acpi_pm_device_run_wake-Enable/disableremotewakeupforgivendevice.+*@dev:Devicetoenable/disabletheplatformtowakeup.+*@enable:Whethertoenableordisablethewakeupfunctionality.*/intacpi_pm_device_run_wake(structdevice*phys_dev,boolenable){-structacpi_device*dev;+structacpi_device*adev;acpi_handlehandle;if(!device_run_wake(phys_dev))return-EINVAL;handle=DEVICE_ACPI_HANDLE(phys_dev);-if(!handle||ACPI_FAILURE(acpi_bus_get_device(handle,&dev))){-dev_dbg(phys_dev,"ACPI handle has no context in %s!\n",+if(!handle||ACPI_FAILURE(acpi_bus_get_device(handle,&adev))){+dev_dbg(phys_dev,"ACPI handle without context in %s!\n",__func__);return-ENODEV;}-if(enable){-acpi_enable_wakeup_device_power(dev,ACPI_STATE_S0);-acpi_enable_gpe(dev->wakeup.gpe_device,dev->wakeup.gpe_number);-}else{-acpi_disable_gpe(dev->wakeup.gpe_device,dev->wakeup.gpe_number);-acpi_disable_wakeup_device_power(dev);-}--return0;+return__acpi_device_run_wake(adev,enable);}EXPORT_SYMBOL(acpi_pm_device_run_wake);#endif /* CONFIG_PM_RUNTIME */++#ifdef CONFIG_PM_SLEEP+/**+*__acpi_device_sleep_wake-Enableordisabledevicetowakeupthesystem.+*@dev:Devicetoenable/desibletowakeupthesystem.+*@target_state:Systemstatethedeviceissupposedtowakeupfrom.+*@enable:Whethertoenableordisable@devtowakeupthesystem.+*/+int__acpi_device_sleep_wake(structacpi_device*adev,u32target_state,+boolenable)+{+returnenable?+acpi_enable_wakeup_device_power(adev,target_state):+acpi_disable_wakeup_device_power(adev);+}+#endif /* CONFIG_PM_SLEEP */
@@ -739,15 +739,13 @@ int acpi_pm_device_sleep_wake(struct devhandle=DEVICE_ACPI_HANDLE(dev);if(!handle||ACPI_FAILURE(acpi_bus_get_device(handle,&adev))){-dev_dbg(dev,"ACPI handle has no context in %s!\n",__func__);+dev_dbg(dev,"ACPI handle without context in %s!\n",__func__);return-ENODEV;}-error=enable?-acpi_enable_wakeup_device_power(adev,acpi_target_sleep_state):-acpi_disable_wakeup_device_power(adev);+error=__acpi_device_sleep_wake(adev,acpi_target_sleep_state,enable);if(!error)-dev_info(dev,"wake-up capability %s by ACPI\n",+dev_info(dev,"System wakeup %s by ACPI\n",enable?"enabled":"disabled");returnerror;
On Mon, Oct 29, 2012 at 10:11:20AM +0100, Rafael J. Wysocki wrote:
From: Rafael J. Wysocki <redacted>
If the caller of acpi_bus_set_power() already has a pointer to the
struct acpi_device object corresponding to the device in question, it
doesn't make sense for it to go through acpi_bus_get_device(), which
may be costly, because it involves acquiring the global ACPI
namespace mutex.
For this reason, export the function operating on struct acpi_device
objects used internally by acpi_bus_set_power(), so that it may be
called instead of acpi_bus_set_power() in the above case, and change
its name to acpi_device_set_power().
Additionally, introduce two inline wrappers for checking ACPI PM
capabilities of devices represented by struct acpi_device objects.
What about adding yet another wrapper to check power off capability of
the device? If device has _PS3 or _PRx, it means the device can be
powered off from ACPI's perspective. This is useful for ZPODD when
deciding if platform has the required ability to support it.
Thanks,
Aaron
From: Rafael J. Wysocki <hidden> Date: 2012-10-30 15:16:11
On Tuesday, October 30, 2012 03:28:45 PM Aaron Lu wrote:
On Mon, Oct 29, 2012 at 10:11:20AM +0100, Rafael J. Wysocki wrote:
quoted
From: Rafael J. Wysocki <redacted>
If the caller of acpi_bus_set_power() already has a pointer to the
struct acpi_device object corresponding to the device in question, it
doesn't make sense for it to go through acpi_bus_get_device(), which
may be costly, because it involves acquiring the global ACPI
namespace mutex.
For this reason, export the function operating on struct acpi_device
objects used internally by acpi_bus_set_power(), so that it may be
called instead of acpi_bus_set_power() in the above case, and change
its name to acpi_device_set_power().
Additionally, introduce two inline wrappers for checking ACPI PM
capabilities of devices represented by struct acpi_device objects.
What about adding yet another wrapper to check power off capability of
the device? If device has _PS3 or _PRx, it means the device can be
powered off from ACPI's perspective. This is useful for ZPODD when
deciding if platform has the required ability to support it.
Sure, no problem with that. Perhaps you can cut a patch for that
on top of this series?
Rafael
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
On Tuesday, October 30, 2012 03:28:45 PM Aaron Lu wrote:
quoted
On Mon, Oct 29, 2012 at 10:11:20AM +0100, Rafael J. Wysocki wrote:
quoted
From: Rafael J. Wysocki <redacted>
If the caller of acpi_bus_set_power() already has a pointer to the
struct acpi_device object corresponding to the device in question, it
doesn't make sense for it to go through acpi_bus_get_device(), which
may be costly, because it involves acquiring the global ACPI
namespace mutex.
For this reason, export the function operating on struct acpi_device
objects used internally by acpi_bus_set_power(), so that it may be
called instead of acpi_bus_set_power() in the above case, and change
its name to acpi_device_set_power().
Additionally, introduce two inline wrappers for checking ACPI PM
capabilities of devices represented by struct acpi_device objects.
What about adding yet another wrapper to check power off capability of
the device? If device has _PS3 or _PRx, it means the device can be
powered off from ACPI's perspective. This is useful for ZPODD when
deciding if platform has the required ability to support it.
Sure, no problem with that. Perhaps you can cut a patch for that
on top of this series?
Do you think it is reasonable to add a new field to acpi_state.flags to
represent if we, as OSPM, have a way to put the device into a ACPI
device state? This field can be set once in acpi_bus_get_power_flags and
used afterwards.
The valid field of acpi_state.flags is what we have today, and it means
whether this ACPI device state is valid for the device, but not that if
OSPM can actually put the device into that power state.
Thanks,
Aaron
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Rafael J. Wysocki <hidden> Date: 2012-11-02 11:15:38
On Friday, November 02, 2012 01:17:10 PM Aaron Lu wrote:
On 10/30/2012 11:20 PM, Rafael J. Wysocki wrote:
quoted
On Tuesday, October 30, 2012 03:28:45 PM Aaron Lu wrote:
quoted
On Mon, Oct 29, 2012 at 10:11:20AM +0100, Rafael J. Wysocki wrote:
quoted
From: Rafael J. Wysocki <redacted>
If the caller of acpi_bus_set_power() already has a pointer to the
struct acpi_device object corresponding to the device in question, it
doesn't make sense for it to go through acpi_bus_get_device(), which
may be costly, because it involves acquiring the global ACPI
namespace mutex.
For this reason, export the function operating on struct acpi_device
objects used internally by acpi_bus_set_power(), so that it may be
called instead of acpi_bus_set_power() in the above case, and change
its name to acpi_device_set_power().
Additionally, introduce two inline wrappers for checking ACPI PM
capabilities of devices represented by struct acpi_device objects.
What about adding yet another wrapper to check power off capability of
the device? If device has _PS3 or _PRx, it means the device can be
powered off from ACPI's perspective. This is useful for ZPODD when
deciding if platform has the required ability to support it.
Sure, no problem with that. Perhaps you can cut a patch for that
on top of this series?
Do you think it is reasonable to add a new field to acpi_state.flags to
represent if we, as OSPM, have a way to put the device into a ACPI
device state? This field can be set once in acpi_bus_get_power_flags and
used afterwards.
The valid field of acpi_state.flags is what we have today, and it means
whether this ACPI device state is valid for the device, but not that if
OSPM can actually put the device into that power state.
Yes, I think that adding such a new flag would make sense.
Thanks,
Rafael
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
This patch doesn't apply...
I'm trying on Linus' master branch, HEAD is v3.7-rc4, and I've merged
your pm-qos branch on top of v3.7-rc4.
Thanks,
Aaron
On Mon, Oct 29, 2012 at 10:09:09AM +0100, Rafael J. Wysocki wrote:
quoted hunk
From: Rafael J. Wysocki <redacted>
The ACPI function for choosing device power state is now located
in drivers/acpi/sleep.c, but drivers/acpi/device_pm.c is a more
logical place for it, so move it there.
However, instead of moving the function entirely, move its core only
under a different name and with a different list of arguments, so
that it is more flexible, and leave a wrapper around it in the
original location.
Signed-off-by: Rafael J. Wysocki <redacted>
---
drivers/acpi/device_pm.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/sleep.c | 88 +-------------------------------------
include/acpi/acpi_bus.h | 15 ++++++
3 files changed, 124 insertions(+), 86 deletions(-)
Index: linux/drivers/acpi/device_pm.c
===================================================================
@@ -89,3 +91,108 @@ acpi_status acpi_remove_pm_notifier(strumutex_unlock(&acpi_pm_notifier_lock);returnstatus;}++/**+*acpi_device_power_state-GetpreferredpowerstateofACPIdevice.+*@dev:Devicewhosepreferredtargetpowerstatetoreturn.+*@adev:ACPIdevicenodecorrespondingto@dev.+*@target_state:Systemstatetomatchtheresultantdevicestate.+*@d_max_in:Deepestlow-powerstatetotakeintoconsideration.+*@d_min_p:Locationtostoretheupperlimitoftheallowedstatesrange.+*Returnvalue:Preferredpowerstateofthedeviceonsuccess,-ENODEV+*(ifthere'sno'structacpi_device'for@dev)or-EINVALonfailure+*+*Findthelowestpower(highestnumber)ACPIdevicepowerstatethatthe+*devicecanbeinwhilethesystemisinthestaterepresentedby+*@target_state.If@d_min_pisset,thehighestpower(lowestnumber)device+*powerstatethat@devcanbeinforthegivensystemsleepstateisstored+*atthelocationpointedtobyit.+*+*Callersmustensurethat@devand@adevarevalidpointersandthat@adev+*actuallycorrespondsto@devbeforeusingthisfunction.+*/+intacpi_device_power_state(structdevice*dev,structacpi_device*adev,+u32target_state,intd_max_in,int*d_min_p)+{+characpi_method[]="_SxD";+unsignedlonglongd_min,d_max;+boolwakeup=false;++if(d_max_in<ACPI_STATE_D0||d_max_in>ACPI_STATE_D3)+return-EINVAL;++if(d_max_in>ACPI_STATE_D3_HOT){+enumpm_qos_flags_statusstat;++stat=dev_pm_qos_flags(dev,PM_QOS_FLAG_NO_POWER_OFF);+if(stat==PM_QOS_FLAGS_ALL)+d_max_in=ACPI_STATE_D3_HOT;+}++acpi_method[2]='0'+target_state;+/*+*IfthesleepstateisS0,thelowestlimitfromACPIisD3,+*butifthedevicehas_S0W,wewillusethevaluefrom_S0W+*asthelowestlimitfromACPI.Finally,wewillconstrain+*thelowestlimitwiththespecifiedone.+*/+d_min=ACPI_STATE_D0;+d_max=ACPI_STATE_D3;++/*+*Ifpresent,_SxDmethodsreturntheminimumD-state(highestpower+*state)wecanuseforthecorrespondingS-states.Otherwise,the+*minimumD-stateisD0(ACPI3.x).+*+*NOTE:Werelyonacpi_evaluate_integer()notclobberingtheinteger+*provided--that'sourfaultrecovery,weignoreretval.+*/+if(target_state>ACPI_STATE_S0){+acpi_evaluate_integer(adev->handle,acpi_method,NULL,&d_min);+wakeup=device_may_wakeup(dev)&&adev->wakeup.flags.valid+&&adev->wakeup.sleep_state>=target_state;+}elseif(dev_pm_qos_flags(dev,PM_QOS_FLAG_REMOTE_WAKEUP)!=+PM_QOS_FLAGS_NONE){+wakeup=adev->wakeup.flags.valid;+}++/*+*If_PRWsayswecanwakeupthesystemfromthetargetsleepstate,+*theD-statereturnedby_SxDissufficientforthat(weassumea+*wakeup-awaredriverifwakeisset).Still,if_SxWexists+*(ACPI3.x),itshouldreturnthemaximum(lowestpower)D-statethat+*canwakethesystem._S0Wmaybevalid,too.+*/+if(wakeup){+acpi_statusstatus;++acpi_method[3]='W';+status=acpi_evaluate_integer(adev->handle,acpi_method,NULL,+&d_max);+if(ACPI_FAILURE(status)){+if(target_state!=ACPI_STATE_S0||+status!=AE_NOT_FOUND)+d_max=d_min;+}elseif(d_max<d_min){+/* Warn the user of the broken DSDT */+printk(KERN_WARNING"ACPI: Wrong value from %s\n",+acpi_method);+/* Sanitize it */+d_min=d_max;+}+}++if(d_max_in<d_min)+return-EINVAL;+if(d_min_p)+*d_min_p=d_min;+/* constrain d_max with specified lowest limit (max number) */+if(d_max>d_max_in){+for(d_max=d_max_in;d_max>d_min;d_max--){+if(adev->power.states[d_max].flags.valid)+break;+}+}+returnd_max;+}+EXPORT_SYMBOL_GPL(acpi_device_power_state);
@@ -706,101 +705,20 @@ int acpi_suspend(u32 acpi_state)*Returnvalue:Preferredpowerstateofthedeviceonsuccess,-ENODEV*(ifthere'sno'structacpi_device'for@dev)or-EINVALonfailure*-*Findthelowestpower(highestnumber)ACPIdevicepowerstatethatthe-*devicecanbeinwhilethesystemisinthesleepstaterepresented-*by%acpi_target_sleep_state.If@d_min_pisset,thehighestpower(lowest-*number)devicepowerstatethat@devcanbeinforthegivensystemsleep-*stateisstoredatthelocationpointedtobyit.-**Thecallermustensurethat@devisvalidbeforeusingthisfunction.*/intacpi_pm_device_sleep_state(structdevice*dev,int*d_min_p,intd_max_in){acpi_handlehandle=DEVICE_ACPI_HANDLE(dev);structacpi_device*adev;-characpi_method[]="_SxD";-unsignedlonglongd_min,d_max;-boolwakeup=false;-if(d_max_in<ACPI_STATE_D0||d_max_in>ACPI_STATE_D3)-return-EINVAL;if(!handle||ACPI_FAILURE(acpi_bus_get_device(handle,&adev))){-printk(KERN_DEBUG"ACPI handle has no context!\n");+dev_dbg(dev,"ACPI handle without context in %s!\n",__func__);return-ENODEV;}-if(d_max_in>ACPI_STATE_D3_HOT){-enumpm_qos_flags_statusstat;--stat=dev_pm_qos_flags(dev,PM_QOS_FLAG_NO_POWER_OFF);-if(stat==PM_QOS_FLAGS_ALL)-d_max_in=ACPI_STATE_D3_HOT;-}--acpi_method[2]='0'+acpi_target_sleep_state;-/*-*IfthesleepstateisS0,thelowestlimitfromACPIisD3,-*butifthedevicehas_S0W,wewillusethevaluefrom_S0W-*asthelowestlimitfromACPI.Finally,wewillconstrain-*thelowestlimitwiththespecifiedone.-*/-d_min=ACPI_STATE_D0;-d_max=ACPI_STATE_D3;-/*-*Ifpresent,_SxDmethodsreturntheminimumD-state(highestpower-*state)wecanuseforthecorrespondingS-states.Otherwise,the-*minimumD-stateisD0(ACPI3.x).-*-*NOTE:Werelyonacpi_evaluate_integer()notclobberingtheinteger-*provided--that'sourfaultrecovery,weignoreretval.-*/-if(acpi_target_sleep_state>ACPI_STATE_S0){-acpi_evaluate_integer(handle,acpi_method,NULL,&d_min);-wakeup=device_may_wakeup(dev)&&adev->wakeup.flags.valid-&&adev->wakeup.sleep_state>=acpi_target_sleep_state;-}elseif(dev_pm_qos_flags(dev,PM_QOS_FLAG_REMOTE_WAKEUP)!=-PM_QOS_FLAGS_NONE){-wakeup=adev->wakeup.flags.valid;-}--/*-*If_PRWsayswecanwakeupthesystemfromthetargetsleepstate,-*theD-statereturnedby_SxDissufficientforthat(weassumea-*wakeup-awaredriverifwakeisset).Still,if_SxWexists-*(ACPI3.x),itshouldreturnthemaximum(lowestpower)D-statethat-*canwakethesystem._S0Wmaybevalid,too.-*/-if(wakeup){-acpi_statusstatus;--acpi_method[3]='W';-status=acpi_evaluate_integer(handle,acpi_method,NULL,-&d_max);-if(ACPI_FAILURE(status)){-if(acpi_target_sleep_state!=ACPI_STATE_S0||-status!=AE_NOT_FOUND)-d_max=d_min;-}elseif(d_max<d_min){-/* Warn the user of the broken DSDT */-printk(KERN_WARNING"ACPI: Wrong value from %s\n",-acpi_method);-/* Sanitize it */-d_min=d_max;-}-}--if(d_max_in<d_min)-return-EINVAL;-if(d_min_p)-*d_min_p=d_min;-/* constrain d_max with specified lowest limit (max number) */-if(d_max>d_max_in){-for(d_max=d_max_in;d_max>d_min;d_max--){-if(adev->power.states[d_max].flags.valid)-break;-}-}-returnd_max;+returnacpi_device_power_state(dev,adev,acpi_target_sleep_state,+d_max_in,d_min_p);}EXPORT_SYMBOL(acpi_pm_device_sleep_state);#endif /* CONFIG_PM */
From: Rafael J. Wysocki <hidden> Date: 2012-11-06 12:58:54
On Tuesday, November 06, 2012 12:56:07 PM Aaron Lu wrote:
This patch doesn't apply...
I'm trying on Linus' master branch, HEAD is v3.7-rc4, and I've merged
your pm-qos branch on top of v3.7-rc4.
Well, it applies for me.
You can use the linux-next branch of my tree instead. It may contain
some fixes made after this patch had been sent.
Thanks,
Rafael
On Mon, Oct 29, 2012 at 10:09:09AM +0100, Rafael J. Wysocki wrote:
quoted
From: Rafael J. Wysocki <redacted>
The ACPI function for choosing device power state is now located
in drivers/acpi/sleep.c, but drivers/acpi/device_pm.c is a more
logical place for it, so move it there.
However, instead of moving the function entirely, move its core only
under a different name and with a different list of arguments, so
that it is more flexible, and leave a wrapper around it in the
original location.
Signed-off-by: Rafael J. Wysocki <redacted>
---
drivers/acpi/device_pm.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/sleep.c | 88 +-------------------------------------
include/acpi/acpi_bus.h | 15 ++++++
3 files changed, 124 insertions(+), 86 deletions(-)
Index: linux/drivers/acpi/device_pm.c
===================================================================
@@ -89,3 +91,108 @@ acpi_status acpi_remove_pm_notifier(strumutex_unlock(&acpi_pm_notifier_lock);returnstatus;}++/**+*acpi_device_power_state-GetpreferredpowerstateofACPIdevice.+*@dev:Devicewhosepreferredtargetpowerstatetoreturn.+*@adev:ACPIdevicenodecorrespondingto@dev.+*@target_state:Systemstatetomatchtheresultantdevicestate.+*@d_max_in:Deepestlow-powerstatetotakeintoconsideration.+*@d_min_p:Locationtostoretheupperlimitoftheallowedstatesrange.+*Returnvalue:Preferredpowerstateofthedeviceonsuccess,-ENODEV+*(ifthere'sno'structacpi_device'for@dev)or-EINVALonfailure+*+*Findthelowestpower(highestnumber)ACPIdevicepowerstatethatthe+*devicecanbeinwhilethesystemisinthestaterepresentedby+*@target_state.If@d_min_pisset,thehighestpower(lowestnumber)device+*powerstatethat@devcanbeinforthegivensystemsleepstateisstored+*atthelocationpointedtobyit.+*+*Callersmustensurethat@devand@adevarevalidpointersandthat@adev+*actuallycorrespondsto@devbeforeusingthisfunction.+*/+intacpi_device_power_state(structdevice*dev,structacpi_device*adev,+u32target_state,intd_max_in,int*d_min_p)+{+characpi_method[]="_SxD";+unsignedlonglongd_min,d_max;+boolwakeup=false;++if(d_max_in<ACPI_STATE_D0||d_max_in>ACPI_STATE_D3)+return-EINVAL;++if(d_max_in>ACPI_STATE_D3_HOT){+enumpm_qos_flags_statusstat;++stat=dev_pm_qos_flags(dev,PM_QOS_FLAG_NO_POWER_OFF);+if(stat==PM_QOS_FLAGS_ALL)+d_max_in=ACPI_STATE_D3_HOT;+}++acpi_method[2]='0'+target_state;+/*+*IfthesleepstateisS0,thelowestlimitfromACPIisD3,+*butifthedevicehas_S0W,wewillusethevaluefrom_S0W+*asthelowestlimitfromACPI.Finally,wewillconstrain+*thelowestlimitwiththespecifiedone.+*/+d_min=ACPI_STATE_D0;+d_max=ACPI_STATE_D3;++/*+*Ifpresent,_SxDmethodsreturntheminimumD-state(highestpower+*state)wecanuseforthecorrespondingS-states.Otherwise,the+*minimumD-stateisD0(ACPI3.x).+*+*NOTE:Werelyonacpi_evaluate_integer()notclobberingtheinteger+*provided--that'sourfaultrecovery,weignoreretval.+*/+if(target_state>ACPI_STATE_S0){+acpi_evaluate_integer(adev->handle,acpi_method,NULL,&d_min);+wakeup=device_may_wakeup(dev)&&adev->wakeup.flags.valid+&&adev->wakeup.sleep_state>=target_state;+}elseif(dev_pm_qos_flags(dev,PM_QOS_FLAG_REMOTE_WAKEUP)!=+PM_QOS_FLAGS_NONE){+wakeup=adev->wakeup.flags.valid;+}++/*+*If_PRWsayswecanwakeupthesystemfromthetargetsleepstate,+*theD-statereturnedby_SxDissufficientforthat(weassumea+*wakeup-awaredriverifwakeisset).Still,if_SxWexists+*(ACPI3.x),itshouldreturnthemaximum(lowestpower)D-statethat+*canwakethesystem._S0Wmaybevalid,too.+*/+if(wakeup){+acpi_statusstatus;++acpi_method[3]='W';+status=acpi_evaluate_integer(adev->handle,acpi_method,NULL,+&d_max);+if(ACPI_FAILURE(status)){+if(target_state!=ACPI_STATE_S0||+status!=AE_NOT_FOUND)+d_max=d_min;+}elseif(d_max<d_min){+/* Warn the user of the broken DSDT */+printk(KERN_WARNING"ACPI: Wrong value from %s\n",+acpi_method);+/* Sanitize it */+d_min=d_max;+}+}++if(d_max_in<d_min)+return-EINVAL;+if(d_min_p)+*d_min_p=d_min;+/* constrain d_max with specified lowest limit (max number) */+if(d_max>d_max_in){+for(d_max=d_max_in;d_max>d_min;d_max--){+if(adev->power.states[d_max].flags.valid)+break;+}+}+returnd_max;+}+EXPORT_SYMBOL_GPL(acpi_device_power_state);
@@ -706,101 +705,20 @@ int acpi_suspend(u32 acpi_state)*Returnvalue:Preferredpowerstateofthedeviceonsuccess,-ENODEV*(ifthere'sno'structacpi_device'for@dev)or-EINVALonfailure*-*Findthelowestpower(highestnumber)ACPIdevicepowerstatethatthe-*devicecanbeinwhilethesystemisinthesleepstaterepresented-*by%acpi_target_sleep_state.If@d_min_pisset,thehighestpower(lowest-*number)devicepowerstatethat@devcanbeinforthegivensystemsleep-*stateisstoredatthelocationpointedtobyit.-**Thecallermustensurethat@devisvalidbeforeusingthisfunction.*/intacpi_pm_device_sleep_state(structdevice*dev,int*d_min_p,intd_max_in){acpi_handlehandle=DEVICE_ACPI_HANDLE(dev);structacpi_device*adev;-characpi_method[]="_SxD";-unsignedlonglongd_min,d_max;-boolwakeup=false;-if(d_max_in<ACPI_STATE_D0||d_max_in>ACPI_STATE_D3)-return-EINVAL;if(!handle||ACPI_FAILURE(acpi_bus_get_device(handle,&adev))){-printk(KERN_DEBUG"ACPI handle has no context!\n");+dev_dbg(dev,"ACPI handle without context in %s!\n",__func__);return-ENODEV;}-if(d_max_in>ACPI_STATE_D3_HOT){-enumpm_qos_flags_statusstat;--stat=dev_pm_qos_flags(dev,PM_QOS_FLAG_NO_POWER_OFF);-if(stat==PM_QOS_FLAGS_ALL)-d_max_in=ACPI_STATE_D3_HOT;-}--acpi_method[2]='0'+acpi_target_sleep_state;-/*-*IfthesleepstateisS0,thelowestlimitfromACPIisD3,-*butifthedevicehas_S0W,wewillusethevaluefrom_S0W-*asthelowestlimitfromACPI.Finally,wewillconstrain-*thelowestlimitwiththespecifiedone.-*/-d_min=ACPI_STATE_D0;-d_max=ACPI_STATE_D3;-/*-*Ifpresent,_SxDmethodsreturntheminimumD-state(highestpower-*state)wecanuseforthecorrespondingS-states.Otherwise,the-*minimumD-stateisD0(ACPI3.x).-*-*NOTE:Werelyonacpi_evaluate_integer()notclobberingtheinteger-*provided--that'sourfaultrecovery,weignoreretval.-*/-if(acpi_target_sleep_state>ACPI_STATE_S0){-acpi_evaluate_integer(handle,acpi_method,NULL,&d_min);-wakeup=device_may_wakeup(dev)&&adev->wakeup.flags.valid-&&adev->wakeup.sleep_state>=acpi_target_sleep_state;-}elseif(dev_pm_qos_flags(dev,PM_QOS_FLAG_REMOTE_WAKEUP)!=-PM_QOS_FLAGS_NONE){-wakeup=adev->wakeup.flags.valid;-}--/*-*If_PRWsayswecanwakeupthesystemfromthetargetsleepstate,-*theD-statereturnedby_SxDissufficientforthat(weassumea-*wakeup-awaredriverifwakeisset).Still,if_SxWexists-*(ACPI3.x),itshouldreturnthemaximum(lowestpower)D-statethat-*canwakethesystem._S0Wmaybevalid,too.-*/-if(wakeup){-acpi_statusstatus;--acpi_method[3]='W';-status=acpi_evaluate_integer(handle,acpi_method,NULL,-&d_max);-if(ACPI_FAILURE(status)){-if(acpi_target_sleep_state!=ACPI_STATE_S0||-status!=AE_NOT_FOUND)-d_max=d_min;-}elseif(d_max<d_min){-/* Warn the user of the broken DSDT */-printk(KERN_WARNING"ACPI: Wrong value from %s\n",-acpi_method);-/* Sanitize it */-d_min=d_max;-}-}--if(d_max_in<d_min)-return-EINVAL;-if(d_min_p)-*d_min_p=d_min;-/* constrain d_max with specified lowest limit (max number) */-if(d_max>d_max_in){-for(d_max=d_max_in;d_max>d_min;d_max--){-if(adev->power.states[d_max].flags.valid)-break;-}-}-returnd_max;+returnacpi_device_power_state(dev,adev,acpi_target_sleep_state,+d_max_in,d_min_p);}EXPORT_SYMBOL(acpi_pm_device_sleep_state);#endif /* CONFIG_PM */
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
From: David Rientjes <rientjes@google.com> Date: 2012-11-06 19:52:54
Commit b87b49cd0efd ("ACPI / PM: Move device PM functions related to sleep
states") declared acpi_target_system_state() for CONFIG_PM_SLEEP whereas
it is only defined for CONFIG_ACPI_SLEEP, resulting in the following link
error:
drivers/built-in.o: In function `acpi_pm_device_sleep_wake':
drivers/acpi/device_pm.c:342: undefined reference to `acpi_target_system_state'
drivers/built-in.o: In function `acpi_dev_suspend_late':
drivers/acpi/device_pm.c:501: undefined reference to `acpi_target_system_state'
drivers/built-in.o: In function `acpi_pm_device_sleep_state':
drivers/acpi/device_pm.c:221: undefined reference to `acpi_target_system_state'
Define it only for CONFIG_ACPI_SLEEP and fallback to a dummy definition
for other configs.
Signed-off-by: David Rientjes <rientjes@google.com>
---
include/acpi/acpi_bus.h | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)
From: David Rientjes <rientjes@google.com> Date: 2012-11-08 19:20:09
Commit b87b49cd0efd ("ACPI / PM: Move device PM functions related to sleep
states") declared acpi_target_system_state() for CONFIG_PM_SLEEP whereas
it is only defined for CONFIG_ACPI_SLEEP, resulting in the following link
error:
drivers/built-in.o: In function `acpi_pm_device_sleep_wake':
drivers/acpi/device_pm.c:342: undefined reference to `acpi_target_system_state'
drivers/built-in.o: In function `acpi_dev_suspend_late':
drivers/acpi/device_pm.c:501: undefined reference to `acpi_target_system_state'
drivers/built-in.o: In function `acpi_pm_device_sleep_state':
drivers/acpi/device_pm.c:221: undefined reference to `acpi_target_system_state'
Define it only for CONFIG_ACPI_SLEEP and fallback to a dummy definition
for other configs.
Signed-off-by: David Rientjes <rientjes@google.com>
---
include/acpi/acpi_bus.h | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)
From: Rafael J. Wysocki <hidden> Date: 2012-11-08 21:11:25
On Thursday, November 08, 2012 11:20:01 AM David Rientjes wrote:
Commit b87b49cd0efd ("ACPI / PM: Move device PM functions related to sleep
states") declared acpi_target_system_state() for CONFIG_PM_SLEEP whereas
it is only defined for CONFIG_ACPI_SLEEP, resulting in the following link
error:
drivers/built-in.o: In function `acpi_pm_device_sleep_wake':
drivers/acpi/device_pm.c:342: undefined reference to `acpi_target_system_state'
drivers/built-in.o: In function `acpi_dev_suspend_late':
drivers/acpi/device_pm.c:501: undefined reference to `acpi_target_system_state'
drivers/built-in.o: In function `acpi_pm_device_sleep_state':
drivers/acpi/device_pm.c:221: undefined reference to `acpi_target_system_state'
Define it only for CONFIG_ACPI_SLEEP and fallback to a dummy definition
for other configs.
Signed-off-by: David Rientjes <rientjes@google.com>
I've received the patch and will apply it when I get back home from Spain.
Thanks,
Rafael