aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2012-06-22 22:23:48 -0400
committerBjorn Helgaas <bhelgaas@google.com>2012-06-23 12:41:09 -0400
commitee85f543710dd56ce526cb44e39191f32972e5ad (patch)
tree13009358f0260d39c106b6708d6bb49f1d73279f
parentcfaf025112d3856637ff34a767ef785ef5cf2ca9 (diff)
ACPI/PM: specify lowest allowed state for device sleep state
Lower device sleep state can save more power, but has more exit latency too. Sometimes, to satisfy some power QoS and other requirement, we need to constrain the lowest device sleep state. In this patch, a parameter to specify lowest allowed state for acpi_pm_device_sleep_state is added. So that the caller can enforce the constraint via the parameter. This is needed by PCIe D3cold support, where the lowest power state allowed may be D3_HOT instead of default D3_COLD. CC: Len Brown <lenb@kernel.org> CC: linux-acpi@vger.kernel.org Reviewed-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--drivers/acpi/sleep.c24
-rw-r--r--drivers/pci/pci-acpi.c3
-rw-r--r--drivers/pnp/pnpacpi/core.c4
-rw-r--r--include/acpi/acpi_bus.h6
4 files changed, 26 insertions, 11 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 88561029cca8..1cc02ca2af2a 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -716,8 +716,9 @@ int acpi_suspend(u32 acpi_state)
716 * @dev: device to examine; its driver model wakeup flags control 716 * @dev: device to examine; its driver model wakeup flags control
717 * whether it should be able to wake up the system 717 * whether it should be able to wake up the system
718 * @d_min_p: used to store the upper limit of allowed states range 718 * @d_min_p: used to store the upper limit of allowed states range
719 * Return value: preferred power state of the device on success, -ENODEV on 719 * @d_max_in: specify the lowest allowed states
720 * failure (ie. if there's no 'struct acpi_device' for @dev) 720 * Return value: preferred power state of the device on success, -ENODEV
721 * (ie. if there's no 'struct acpi_device' for @dev) or -EINVAL on failure
721 * 722 *
722 * Find the lowest power (highest number) ACPI device power state that 723 * Find the lowest power (highest number) ACPI device power state that
723 * device @dev can be in while the system is in the sleep state represented 724 * device @dev can be in while the system is in the sleep state represented
@@ -732,13 +733,15 @@ int acpi_suspend(u32 acpi_state)
732 * via @wake. 733 * via @wake.
733 */ 734 */
734 735
735int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p) 736int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in)
736{ 737{
737 acpi_handle handle = DEVICE_ACPI_HANDLE(dev); 738 acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
738 struct acpi_device *adev; 739 struct acpi_device *adev;
739 char acpi_method[] = "_SxD"; 740 char acpi_method[] = "_SxD";
740 unsigned long long d_min, d_max; 741 unsigned long long d_min, d_max;
741 742
743 if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3)
744 return -EINVAL;
742 if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { 745 if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
743 printk(KERN_DEBUG "ACPI handle has no context!\n"); 746 printk(KERN_DEBUG "ACPI handle has no context!\n");
744 return -ENODEV; 747 return -ENODEV;
@@ -746,8 +749,10 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
746 749
747 acpi_method[2] = '0' + acpi_target_sleep_state; 750 acpi_method[2] = '0' + acpi_target_sleep_state;
748 /* 751 /*
749 * If the sleep state is S0, we will return D3, but if the device has 752 * If the sleep state is S0, the lowest limit from ACPI is D3,
750 * _S0W, we will use the value from _S0W 753 * but if the device has _S0W, we will use the value from _S0W
754 * as the lowest limit from ACPI. Finally, we will constrain
755 * the lowest limit with the specified one.
751 */ 756 */
752 d_min = ACPI_STATE_D0; 757 d_min = ACPI_STATE_D0;
753 d_max = ACPI_STATE_D3; 758 d_max = ACPI_STATE_D3;
@@ -791,8 +796,17 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
791 } 796 }
792 } 797 }
793 798
799 if (d_max_in < d_min)
800 return -EINVAL;
794 if (d_min_p) 801 if (d_min_p)
795 *d_min_p = d_min; 802 *d_min_p = d_min;
803 /* constrain d_max with specified lowest limit (max number) */
804 if (d_max > d_max_in) {
805 for (d_max = d_max_in; d_max > d_min; d_max--) {
806 if (adev->power.states[d_max].flags.valid)
807 break;
808 }
809 }
796 return d_max; 810 return d_max;
797} 811}
798#endif /* CONFIG_PM */ 812#endif /* CONFIG_PM */
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 61e2fefeedab..a9efebc586b4 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -189,7 +189,8 @@ static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev)
189{ 189{
190 int acpi_state; 190 int acpi_state;
191 191
192 acpi_state = acpi_pm_device_sleep_state(&pdev->dev, NULL); 192 acpi_state = acpi_pm_device_sleep_state(&pdev->dev, NULL,
193 ACPI_STATE_D3);
193 if (acpi_state < 0) 194 if (acpi_state < 0)
194 return PCI_POWER_ERROR; 195 return PCI_POWER_ERROR;
195 196
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index d21e8f59c84e..507a8e2b9a4c 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -170,8 +170,8 @@ static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
170 } 170 }
171 171
172 if (acpi_bus_power_manageable(handle)) { 172 if (acpi_bus_power_manageable(handle)) {
173 int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL); 173 int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL,
174 174 ACPI_STATE_D3);
175 if (power_state < 0) 175 if (power_state < 0)
176 power_state = (state.event == PM_EVENT_ON) ? 176 power_state = (state.event == PM_EVENT_ON) ?
177 ACPI_STATE_D0 : ACPI_STATE_D3; 177 ACPI_STATE_D0 : ACPI_STATE_D3;
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 9e6e1c6eb60a..16bd68504ff7 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -414,13 +414,13 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev, int state);
414int acpi_disable_wakeup_device_power(struct acpi_device *dev); 414int acpi_disable_wakeup_device_power(struct acpi_device *dev);
415 415
416#ifdef CONFIG_PM 416#ifdef CONFIG_PM
417int acpi_pm_device_sleep_state(struct device *, int *); 417int acpi_pm_device_sleep_state(struct device *, int *, int);
418#else 418#else
419static inline int acpi_pm_device_sleep_state(struct device *d, int *p) 419static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m)
420{ 420{
421 if (p) 421 if (p)
422 *p = ACPI_STATE_D0; 422 *p = ACPI_STATE_D0;
423 return ACPI_STATE_D3; 423 return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3) ? m : ACPI_STATE_D0;
424} 424}
425#endif 425#endif
426 426