diff options
author | Aaron Lu <aaron.lu@intel.com> | 2013-01-25 07:29:35 +0100 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2013-01-25 21:33:33 +0100 |
commit | a7ff60dbe0858496531c75b1544666c099a2b200 (patch) | |
tree | 2bb707b6682c398fbe35db8d3b775272561ddab0 /drivers/ata/libata-acpi.c | |
parent | Revert "libata: export host controller number thru /sys" (diff) | |
download | linux-a7ff60dbe0858496531c75b1544666c099a2b200.tar.xz linux-a7ff60dbe0858496531c75b1544666c099a2b200.zip |
[libata] pm: differentiate system and runtime pm for ata port
We need to do different things for system PM and runtime PM, e.g. we do
not need to enable runtime wake for ZPODD when we are doing system
suspend, etc.
Currently, we use PMSG_SUSPEND for both system suspend and runtime
suspend and PMSG_ON for both system resume and runtime resume. Change
this by using PMSG_AUTO_SUSPEND for runtime suspend and PMSG_AUTO_RESUME
for runtime resume. And since PMSG_ON means no transition, it is changed
to PMSG_RESUME for ata port's system resume.
The ata_acpi_set_state is modified accordingly, and the sata case and
pata case is seperated for easy reading.
Signed-off-by: Aaron Lu <aaron.lu@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata/libata-acpi.c')
-rw-r--r-- | drivers/ata/libata-acpi.c | 76 |
1 files changed, 53 insertions, 23 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 97094496127e..dfd529a30c20 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -836,9 +836,11 @@ void ata_acpi_on_resume(struct ata_port *ap) } } -static int ata_acpi_choose_suspend_state(struct ata_device *dev) +static int ata_acpi_choose_suspend_state(struct ata_device *dev, bool runtime) { int d_max_in = ACPI_STATE_D3_COLD; + if (!runtime) + goto out; /* * For ATAPI, runtime D3 cold is only allowed @@ -848,53 +850,81 @@ static int ata_acpi_choose_suspend_state(struct ata_device *dev) !(zpodd_dev_enabled(dev) && zpodd_zpready(dev))) d_max_in = ACPI_STATE_D3_HOT; +out: return acpi_pm_device_sleep_state(&dev->sdev->sdev_gendev, NULL, d_max_in); } -/** - * ata_acpi_set_state - set the port power state - * @ap: target ATA port - * @state: state, on/off - * - * This function executes the _PS0/_PS3 ACPI method to set the power state. - * ACPI spec requires _PS0 when IDE power on and _PS3 when power off - */ -void ata_acpi_set_state(struct ata_port *ap, pm_message_t state) +static void sata_acpi_set_state(struct ata_port *ap, pm_message_t state) { + bool runtime = PMSG_IS_AUTO(state); struct ata_device *dev; acpi_handle handle; int acpi_state; - /* channel first and then drives for power on and vica versa - for power off */ - handle = ata_ap_acpi_handle(ap); - if (handle && state.event == PM_EVENT_ON) - acpi_bus_set_power(handle, ACPI_STATE_D0); - ata_for_each_dev(dev, &ap->link, ENABLED) { handle = ata_dev_acpi_handle(dev); if (!handle) continue; - if (state.event != PM_EVENT_ON) { - acpi_state = ata_acpi_choose_suspend_state(dev); + if (!(state.event & PM_EVENT_RESUME)) { + acpi_state = ata_acpi_choose_suspend_state(dev, runtime); if (acpi_state == ACPI_STATE_D0) continue; - if (zpodd_dev_enabled(dev) && + if (runtime && zpodd_dev_enabled(dev) && acpi_state == ACPI_STATE_D3_COLD) zpodd_enable_run_wake(dev); acpi_bus_set_power(handle, acpi_state); } else { - if (zpodd_dev_enabled(dev)) + if (runtime && zpodd_dev_enabled(dev)) zpodd_disable_run_wake(dev); acpi_bus_set_power(handle, ACPI_STATE_D0); } } +} + +/* ACPI spec requires _PS0 when IDE power on and _PS3 when power off */ +static void pata_acpi_set_state(struct ata_port *ap, pm_message_t state) +{ + struct ata_device *dev; + acpi_handle port_handle; + + port_handle = ata_ap_acpi_handle(ap); + if (!port_handle) + return; + + /* channel first and then drives for power on and vica versa + for power off */ + if (state.event & PM_EVENT_RESUME) + acpi_bus_set_power(port_handle, ACPI_STATE_D0); + + ata_for_each_dev(dev, &ap->link, ENABLED) { + acpi_handle dev_handle = ata_dev_acpi_handle(dev); + if (!dev_handle) + continue; + + acpi_bus_set_power(dev_handle, state.event & PM_EVENT_RESUME ? + ACPI_STATE_D0 : ACPI_STATE_D3); + } + + if (!(state.event & PM_EVENT_RESUME)) + acpi_bus_set_power(port_handle, ACPI_STATE_D3); +} - handle = ata_ap_acpi_handle(ap); - if (handle && state.event != PM_EVENT_ON) - acpi_bus_set_power(handle, ACPI_STATE_D3); +/** + * ata_acpi_set_state - set the port power state + * @ap: target ATA port + * @state: state, on/off + * + * This function sets a proper ACPI D state for the device on + * system and runtime PM operations. + */ +void ata_acpi_set_state(struct ata_port *ap, pm_message_t state) +{ + if (ap->flags & ATA_FLAG_ACPI_SATA) + sata_acpi_set_state(ap, state); + else + pata_acpi_set_state(ap, state); } /** |