aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/acpi/sleep.c2
-rw-r--r--drivers/ata/libata-acpi.c78
-rw-r--r--drivers/ata/libata-scsi.c3
-rw-r--r--drivers/ata/libata.h4
4 files changed, 83 insertions, 4 deletions
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 88561029cca8..1784cb30e7cf 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -795,6 +795,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
795 *d_min_p = d_min; 795 *d_min_p = d_min;
796 return d_max; 796 return d_max;
797} 797}
798EXPORT_SYMBOL(acpi_pm_device_sleep_state);
798#endif /* CONFIG_PM */ 799#endif /* CONFIG_PM */
799 800
800#ifdef CONFIG_PM_SLEEP 801#ifdef CONFIG_PM_SLEEP
@@ -831,6 +832,7 @@ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable)
831 832
832 return 0; 833 return 0;
833} 834}
835EXPORT_SYMBOL(acpi_pm_device_run_wake);
834 836
835/** 837/**
836 * acpi_pm_device_sleep_wake - enable or disable the system wake-up 838 * acpi_pm_device_sleep_wake - enable or disable the system wake-up
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;
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 22226350cd0c..8ec81ca8f659 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3445,6 +3445,7 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
3445 if (!IS_ERR(sdev)) { 3445 if (!IS_ERR(sdev)) {
3446 dev->sdev = sdev; 3446 dev->sdev = sdev;
3447 scsi_device_put(sdev); 3447 scsi_device_put(sdev);
3448 ata_acpi_bind(dev);
3448 } else { 3449 } else {
3449 dev->sdev = NULL; 3450 dev->sdev = NULL;
3450 } 3451 }
@@ -3541,6 +3542,8 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
3541 mutex_lock(&ap->scsi_host->scan_mutex); 3542 mutex_lock(&ap->scsi_host->scan_mutex);
3542 spin_lock_irqsave(ap->lock, flags); 3543 spin_lock_irqsave(ap->lock, flags);
3543 3544
3545 ata_acpi_unbind(dev);
3546
3544 /* clearing dev->sdev is protected by host lock */ 3547 /* clearing dev->sdev is protected by host lock */
3545 sdev = dev->sdev; 3548 sdev = dev->sdev;
3546 dev->sdev = NULL; 3549 dev->sdev = NULL;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index b0d5294982eb..44a7939b5bb6 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -120,6 +120,8 @@ extern void ata_acpi_on_disable(struct ata_device *dev);
120extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state); 120extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state);
121extern int ata_acpi_register(void); 121extern int ata_acpi_register(void);
122extern void ata_acpi_unregister(void); 122extern void ata_acpi_unregister(void);
123extern void ata_acpi_bind(struct ata_device *dev);
124extern void ata_acpi_unbind(struct ata_device *dev);
123#else 125#else
124static inline void ata_acpi_dissociate(struct ata_host *host) { } 126static inline void ata_acpi_dissociate(struct ata_host *host) { }
125static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; } 127static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
@@ -130,6 +132,8 @@ static inline void ata_acpi_set_state(struct ata_port *ap,
130 pm_message_t state) { } 132 pm_message_t state) { }
131static inline int ata_acpi_register(void) { return 0; } 133static inline int ata_acpi_register(void) { return 0; }
132static void ata_acpi_unregister(void) { } 134static void ata_acpi_unregister(void) { }
135static void ata_acpi_bind(struct ata_device *dev) { }
136static void ata_acpi_unbind(struct ata_device *dev) { }
133#endif 137#endif
134 138
135/* libata-scsi.c */ 139/* libata-scsi.c */