aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-acpi.c
diff options
context:
space:
mode:
authorLin Ming <ming.m.lin@intel.com>2012-06-25 04:13:06 -0400
committerJeff Garzik <jgarzik@redhat.com>2012-06-29 11:38:13 -0400
commit3bd46600a7a7e938c54df8cdbac9910668c7dfb0 (patch)
tree72272f24842f7487b918a47c6e7244e92cad9ae4 /drivers/ata/libata-acpi.c
parentfebe53ba6b781862c12686c7ea1972bdedee457a (diff)
libata-acpi: add ata port runtime D3Cold support
ATA port may support runtime D3Cold state, for example, Zero-power ODD case. This patch adds wakeup notifier and enable/disable run_wake during supend/resume. Signed-off-by: Lin Ming <ming.m.lin@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.c78
1 files changed, 74 insertions, 4 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index bb20fd597eb1..e01807a1ef31 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -16,6 +16,7 @@
16#include <linux/libata.h> 16#include <linux/libata.h>
17#include <linux/pci.h> 17#include <linux/pci.h>
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/pm_runtime.h>
19#include <scsi/scsi_device.h> 20#include <scsi/scsi_device.h>
20#include "libata.h" 21#include "libata.h"
21 22
@@ -853,6 +854,7 @@ void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
853{ 854{
854 struct ata_device *dev; 855 struct ata_device *dev;
855 acpi_handle handle; 856 acpi_handle handle;
857 int acpi_state;
856 858
857 /* channel first and then drives for power on and vica versa 859 /* channel first and then drives for power on and vica versa
858 for power off */ 860 for power off */
@@ -862,10 +864,23 @@ void ata_acpi_set_state(struct ata_port *ap, pm_message_t state)
862 864
863 ata_for_each_dev(dev, &ap->link, ENABLED) { 865 ata_for_each_dev(dev, &ap->link, ENABLED) {
864 handle = ata_dev_acpi_handle(dev); 866 handle = ata_dev_acpi_handle(dev);
865 if (handle) 867 if (!handle)
866 acpi_bus_set_power(handle, 868 continue;
867 state.event == PM_EVENT_ON ? 869
868 ACPI_STATE_D0 : ACPI_STATE_D3); 870 if (state.event != PM_EVENT_ON) {
871 acpi_state = acpi_pm_device_sleep_state(
872 &dev->sdev->sdev_gendev, NULL);
873 if (acpi_state > 0)
874 acpi_bus_set_power(handle, acpi_state);
875 /* TBD: need to check if it's runtime pm request */
876 acpi_pm_device_run_wake(
877 &dev->sdev->sdev_gendev, true);
878 } else {
879 /* Ditto */
880 acpi_pm_device_run_wake(
881 &dev->sdev->sdev_gendev, false);
882 acpi_bus_set_power(handle, ACPI_STATE_D0);
883 }
869 } 884 }
870 885
871 handle = ata_ap_acpi_handle(ap); 886 handle = ata_ap_acpi_handle(ap);
@@ -965,6 +980,61 @@ void ata_acpi_on_disable(struct ata_device *dev)
965 ata_acpi_clear_gtf(dev); 980 ata_acpi_clear_gtf(dev);
966} 981}
967 982
983static void ata_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
984{
985 struct ata_device *ata_dev = context;
986
987 if (event == ACPI_NOTIFY_DEVICE_WAKE && ata_dev &&
988 pm_runtime_suspended(&ata_dev->sdev->sdev_gendev))
989 scsi_autopm_get_device(ata_dev->sdev);
990}
991
992static void ata_acpi_add_pm_notifier(struct ata_device *dev)
993{
994 struct acpi_device *acpi_dev;
995 acpi_handle handle;
996 acpi_status status;
997
998 handle = ata_dev_acpi_handle(dev);
999 if (!handle)
1000 return;
1001
1002 status = acpi_bus_get_device(handle, &acpi_dev);
1003 if (ACPI_SUCCESS(status)) {
1004 acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
1005 ata_acpi_wake_dev, dev);
1006 device_set_run_wake(&dev->sdev->sdev_gendev, true);
1007 }
1008}
1009
1010static void ata_acpi_remove_pm_notifier(struct ata_device *dev)
1011{
1012 struct acpi_device *acpi_dev;
1013 acpi_handle handle;
1014 acpi_status status;
1015
1016 handle = ata_dev_acpi_handle(dev);
1017 if (!handle)
1018 return;
1019
1020 status = acpi_bus_get_device(handle, &acpi_dev);
1021 if (ACPI_SUCCESS(status)) {
1022 device_set_run_wake(&dev->sdev->sdev_gendev, false);
1023 acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
1024 ata_acpi_wake_dev);
1025 }
1026}
1027
1028void ata_acpi_bind(struct ata_device *dev)
1029{
1030 ata_acpi_add_pm_notifier(dev);
1031}
1032
1033void ata_acpi_unbind(struct ata_device *dev)
1034{
1035 ata_acpi_remove_pm_notifier(dev);
1036}
1037
968static int compat_pci_ata(struct ata_port *ap) 1038static int compat_pci_ata(struct ata_port *ap)
969{ 1039{
970 struct device *dev = ap->tdev.parent; 1040 struct device *dev = ap->tdev.parent;