diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/libata-acpi.c | 71 | ||||
-rw-r--r-- | drivers/ata/libata-zpodd.c | 34 |
2 files changed, 34 insertions, 71 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index ef01ac07502e..446b4e761af0 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c | |||
@@ -974,57 +974,6 @@ void ata_acpi_on_disable(struct ata_device *dev) | |||
974 | ata_acpi_clear_gtf(dev); | 974 | ata_acpi_clear_gtf(dev); |
975 | } | 975 | } |
976 | 976 | ||
977 | static void ata_acpi_wake_dev(acpi_handle handle, u32 event, void *context) | ||
978 | { | ||
979 | struct ata_device *ata_dev = context; | ||
980 | |||
981 | if (event == ACPI_NOTIFY_DEVICE_WAKE && ata_dev && | ||
982 | pm_runtime_suspended(&ata_dev->sdev->sdev_gendev)) | ||
983 | scsi_autopm_get_device(ata_dev->sdev); | ||
984 | } | ||
985 | |||
986 | static void ata_acpi_add_pm_notifier(struct ata_device *dev) | ||
987 | { | ||
988 | struct acpi_device *acpi_dev; | ||
989 | acpi_handle handle; | ||
990 | acpi_status status; | ||
991 | |||
992 | handle = ata_dev_acpi_handle(dev); | ||
993 | if (!handle) | ||
994 | return; | ||
995 | |||
996 | status = acpi_bus_get_device(handle, &acpi_dev); | ||
997 | if (ACPI_FAILURE(status)) | ||
998 | return; | ||
999 | |||
1000 | if (dev->sdev->can_power_off) { | ||
1001 | acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
1002 | ata_acpi_wake_dev, dev); | ||
1003 | device_set_run_wake(&dev->sdev->sdev_gendev, true); | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | static void ata_acpi_remove_pm_notifier(struct ata_device *dev) | ||
1008 | { | ||
1009 | struct acpi_device *acpi_dev; | ||
1010 | acpi_handle handle; | ||
1011 | acpi_status status; | ||
1012 | |||
1013 | handle = ata_dev_acpi_handle(dev); | ||
1014 | if (!handle) | ||
1015 | return; | ||
1016 | |||
1017 | status = acpi_bus_get_device(handle, &acpi_dev); | ||
1018 | if (ACPI_FAILURE(status)) | ||
1019 | return; | ||
1020 | |||
1021 | if (dev->sdev->can_power_off) { | ||
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 | |||
1028 | static void ata_acpi_register_power_resource(struct ata_device *dev) | 977 | static void ata_acpi_register_power_resource(struct ata_device *dev) |
1029 | { | 978 | { |
1030 | struct scsi_device *sdev = dev->sdev; | 979 | struct scsi_device *sdev = dev->sdev; |
@@ -1057,13 +1006,11 @@ static void ata_acpi_unregister_power_resource(struct ata_device *dev) | |||
1057 | 1006 | ||
1058 | void ata_acpi_bind(struct ata_device *dev) | 1007 | void ata_acpi_bind(struct ata_device *dev) |
1059 | { | 1008 | { |
1060 | ata_acpi_add_pm_notifier(dev); | ||
1061 | ata_acpi_register_power_resource(dev); | 1009 | ata_acpi_register_power_resource(dev); |
1062 | } | 1010 | } |
1063 | 1011 | ||
1064 | void ata_acpi_unbind(struct ata_device *dev) | 1012 | void ata_acpi_unbind(struct ata_device *dev) |
1065 | { | 1013 | { |
1066 | ata_acpi_remove_pm_notifier(dev); | ||
1067 | ata_acpi_unregister_power_resource(dev); | 1014 | ata_acpi_unregister_power_resource(dev); |
1068 | } | 1015 | } |
1069 | 1016 | ||
@@ -1105,9 +1052,6 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev, | |||
1105 | acpi_handle *handle) | 1052 | acpi_handle *handle) |
1106 | { | 1053 | { |
1107 | struct ata_device *ata_dev; | 1054 | struct ata_device *ata_dev; |
1108 | acpi_status status; | ||
1109 | struct acpi_device *acpi_dev; | ||
1110 | struct acpi_device_power_state *states; | ||
1111 | 1055 | ||
1112 | if (ap->flags & ATA_FLAG_ACPI_SATA) { | 1056 | if (ap->flags & ATA_FLAG_ACPI_SATA) { |
1113 | if (!sata_pmp_attached(ap)) | 1057 | if (!sata_pmp_attached(ap)) |
@@ -1124,21 +1068,6 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev, | |||
1124 | if (!*handle) | 1068 | if (!*handle) |
1125 | return -ENODEV; | 1069 | return -ENODEV; |
1126 | 1070 | ||
1127 | status = acpi_bus_get_device(*handle, &acpi_dev); | ||
1128 | if (ACPI_FAILURE(status)) | ||
1129 | return 0; | ||
1130 | |||
1131 | /* | ||
1132 | * If firmware has _PS3 or _PR3 for this device, | ||
1133 | * and this ata ODD device support device attention, | ||
1134 | * it means this device can be powered off | ||
1135 | */ | ||
1136 | states = acpi_dev->power.states; | ||
1137 | if ((states[ACPI_STATE_D3_HOT].flags.valid || | ||
1138 | states[ACPI_STATE_D3_COLD].flags.explicit_set) && | ||
1139 | ata_dev->flags & ATA_DFLAG_DA) | ||
1140 | sdev->can_power_off = 1; | ||
1141 | |||
1142 | return 0; | 1071 | return 0; |
1143 | } | 1072 | } |
1144 | 1073 | ||
diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index 27eed2f09a8a..9a0d90d09d81 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c | |||
@@ -1,5 +1,7 @@ | |||
1 | #include <linux/libata.h> | 1 | #include <linux/libata.h> |
2 | #include <linux/cdrom.h> | 2 | #include <linux/cdrom.h> |
3 | #include <linux/pm_runtime.h> | ||
4 | #include <scsi/scsi_device.h> | ||
3 | 5 | ||
4 | #include "libata.h" | 6 | #include "libata.h" |
5 | 7 | ||
@@ -12,6 +14,10 @@ enum odd_mech_type { | |||
12 | struct zpodd { | 14 | struct zpodd { |
13 | enum odd_mech_type mech_type; /* init during probe, RO afterwards */ | 15 | enum odd_mech_type mech_type; /* init during probe, RO afterwards */ |
14 | struct ata_device *dev; | 16 | struct ata_device *dev; |
17 | |||
18 | /* The following fields are synchronized by PM core. */ | ||
19 | bool from_notify; /* resumed as a result of | ||
20 | * acpi wake notification */ | ||
15 | }; | 21 | }; |
16 | 22 | ||
17 | /* Per the spec, only slot type and drawer type ODD can be supported */ | 23 | /* Per the spec, only slot type and drawer type ODD can be supported */ |
@@ -68,6 +74,32 @@ static bool odd_can_poweroff(struct ata_device *ata_dev) | |||
68 | return acpi_device_can_poweroff(acpi_dev); | 74 | return acpi_device_can_poweroff(acpi_dev); |
69 | } | 75 | } |
70 | 76 | ||
77 | static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context) | ||
78 | { | ||
79 | struct ata_device *ata_dev = context; | ||
80 | struct zpodd *zpodd = ata_dev->zpodd; | ||
81 | struct device *dev = &ata_dev->sdev->sdev_gendev; | ||
82 | |||
83 | if (event == ACPI_NOTIFY_DEVICE_WAKE && ata_dev && | ||
84 | pm_runtime_suspended(dev)) { | ||
85 | zpodd->from_notify = true; | ||
86 | pm_runtime_resume(dev); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | static void ata_acpi_add_pm_notifier(struct ata_device *dev) | ||
91 | { | ||
92 | acpi_handle handle = ata_dev_acpi_handle(dev); | ||
93 | acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, | ||
94 | zpodd_wake_dev, dev); | ||
95 | } | ||
96 | |||
97 | static void ata_acpi_remove_pm_notifier(struct ata_device *dev) | ||
98 | { | ||
99 | acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->sdev->sdev_gendev); | ||
100 | acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, zpodd_wake_dev); | ||
101 | } | ||
102 | |||
71 | void zpodd_init(struct ata_device *dev) | 103 | void zpodd_init(struct ata_device *dev) |
72 | { | 104 | { |
73 | enum odd_mech_type mech_type; | 105 | enum odd_mech_type mech_type; |
@@ -89,12 +121,14 @@ void zpodd_init(struct ata_device *dev) | |||
89 | 121 | ||
90 | zpodd->mech_type = mech_type; | 122 | zpodd->mech_type = mech_type; |
91 | 123 | ||
124 | ata_acpi_add_pm_notifier(dev); | ||
92 | zpodd->dev = dev; | 125 | zpodd->dev = dev; |
93 | dev->zpodd = zpodd; | 126 | dev->zpodd = zpodd; |
94 | } | 127 | } |
95 | 128 | ||
96 | void zpodd_exit(struct ata_device *dev) | 129 | void zpodd_exit(struct ata_device *dev) |
97 | { | 130 | { |
131 | ata_acpi_remove_pm_notifier(dev); | ||
98 | kfree(dev->zpodd); | 132 | kfree(dev->zpodd); |
99 | dev->zpodd = NULL; | 133 | dev->zpodd = NULL; |
100 | } | 134 | } |