diff options
Diffstat (limited to 'drivers/ata/libata-acpi.c')
-rw-r--r-- | drivers/ata/libata-acpi.c | 177 |
1 files changed, 77 insertions, 100 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 6fc67f7efb22..0ea1018280bd 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c | |||
@@ -17,6 +17,7 @@ | |||
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 <linux/pm_runtime.h> |
20 | #include <linux/pm_qos.h> | ||
20 | #include <scsi/scsi_device.h> | 21 | #include <scsi/scsi_device.h> |
21 | #include "libata.h" | 22 | #include "libata.h" |
22 | 23 | ||
@@ -835,50 +836,95 @@ void ata_acpi_on_resume(struct ata_port *ap) | |||
835 | } | 836 | } |
836 | } | 837 | } |
837 | 838 | ||
838 | /** | 839 | static int ata_acpi_choose_suspend_state(struct ata_device *dev, bool runtime) |
839 | * ata_acpi_set_state - set the port power state | 840 | { |
840 | * @ap: target ATA port | 841 | int d_max_in = ACPI_STATE_D3_COLD; |
841 | * @state: state, on/off | 842 | if (!runtime) |
842 | * | 843 | goto out; |
843 | * This function executes the _PS0/_PS3 ACPI method to set the power state. | 844 | |
844 | * ACPI spec requires _PS0 when IDE power on and _PS3 when power off | 845 | /* |
845 | */ | 846 | * For ATAPI, runtime D3 cold is only allowed |
846 | void ata_acpi_set_state(struct ata_port *ap, pm_message_t state) | 847 | * for ZPODD in zero power ready state |
848 | */ | ||
849 | if (dev->class == ATA_DEV_ATAPI && | ||
850 | !(zpodd_dev_enabled(dev) && zpodd_zpready(dev))) | ||
851 | d_max_in = ACPI_STATE_D3_HOT; | ||
852 | |||
853 | out: | ||
854 | return acpi_pm_device_sleep_state(&dev->sdev->sdev_gendev, | ||
855 | NULL, d_max_in); | ||
856 | } | ||
857 | |||
858 | static void sata_acpi_set_state(struct ata_port *ap, pm_message_t state) | ||
847 | { | 859 | { |
860 | bool runtime = PMSG_IS_AUTO(state); | ||
848 | struct ata_device *dev; | 861 | struct ata_device *dev; |
849 | acpi_handle handle; | 862 | acpi_handle handle; |
850 | int acpi_state; | 863 | int acpi_state; |
851 | 864 | ||
852 | /* channel first and then drives for power on and vica versa | ||
853 | for power off */ | ||
854 | handle = ata_ap_acpi_handle(ap); | ||
855 | if (handle && state.event == PM_EVENT_ON) | ||
856 | acpi_bus_set_power(handle, ACPI_STATE_D0); | ||
857 | |||
858 | ata_for_each_dev(dev, &ap->link, ENABLED) { | 865 | ata_for_each_dev(dev, &ap->link, ENABLED) { |
859 | handle = ata_dev_acpi_handle(dev); | 866 | handle = ata_dev_acpi_handle(dev); |
860 | if (!handle) | 867 | if (!handle) |
861 | continue; | 868 | continue; |
862 | 869 | ||
863 | if (state.event != PM_EVENT_ON) { | 870 | if (!(state.event & PM_EVENT_RESUME)) { |
864 | acpi_state = acpi_pm_device_sleep_state( | 871 | acpi_state = ata_acpi_choose_suspend_state(dev, runtime); |
865 | &dev->sdev->sdev_gendev, NULL, ACPI_STATE_D3); | 872 | if (acpi_state == ACPI_STATE_D0) |
866 | if (acpi_state > 0) | 873 | continue; |
867 | acpi_bus_set_power(handle, acpi_state); | 874 | if (runtime && zpodd_dev_enabled(dev) && |
868 | /* TBD: need to check if it's runtime pm request */ | 875 | acpi_state == ACPI_STATE_D3_COLD) |
869 | acpi_pm_device_run_wake( | 876 | zpodd_enable_run_wake(dev); |
870 | &dev->sdev->sdev_gendev, true); | 877 | acpi_bus_set_power(handle, acpi_state); |
871 | } else { | 878 | } else { |
872 | /* Ditto */ | 879 | if (runtime && zpodd_dev_enabled(dev)) |
873 | acpi_pm_device_run_wake( | 880 | zpodd_disable_run_wake(dev); |
874 | &dev->sdev->sdev_gendev, false); | ||
875 | acpi_bus_set_power(handle, ACPI_STATE_D0); | 881 | acpi_bus_set_power(handle, ACPI_STATE_D0); |
876 | } | 882 | } |
877 | } | 883 | } |
884 | } | ||
878 | 885 | ||
879 | handle = ata_ap_acpi_handle(ap); | 886 | /* ACPI spec requires _PS0 when IDE power on and _PS3 when power off */ |
880 | if (handle && state.event != PM_EVENT_ON) | 887 | static void pata_acpi_set_state(struct ata_port *ap, pm_message_t state) |
881 | acpi_bus_set_power(handle, ACPI_STATE_D3); | 888 | { |
889 | struct ata_device *dev; | ||
890 | acpi_handle port_handle; | ||
891 | |||
892 | port_handle = ata_ap_acpi_handle(ap); | ||
893 | if (!port_handle) | ||
894 | return; | ||
895 | |||
896 | /* channel first and then drives for power on and vica versa | ||
897 | for power off */ | ||
898 | if (state.event & PM_EVENT_RESUME) | ||
899 | acpi_bus_set_power(port_handle, ACPI_STATE_D0); | ||
900 | |||
901 | ata_for_each_dev(dev, &ap->link, ENABLED) { | ||
902 | acpi_handle dev_handle = ata_dev_acpi_handle(dev); | ||
903 | if (!dev_handle) | ||
904 | continue; | ||
905 | |||
906 | acpi_bus_set_power(dev_handle, state.event & PM_EVENT_RESUME ? | ||
907 | ACPI_STATE_D0 : ACPI_STATE_D3); | ||
908 | } | ||
909 | |||
910 | if (!(state.event & PM_EVENT_RESUME)) | ||
911 | acpi_bus_set_power(port_handle, ACPI_STATE_D3); | ||
912 | } | ||
913 | |||
914 | /** | ||
915 | * ata_acpi_set_state - set the port power state | ||
916 | * @ap: target ATA port | ||
917 | * @state: state, on/off | ||
918 | * | ||
919 | * This function sets a proper ACPI D state for the device on | ||
920 | * system and runtime PM operations. | ||
921 | */ | ||
922 | void ata_acpi_set_state(struct ata_port *ap, pm_message_t state) | ||
923 | { | ||
924 | if (ap->flags & ATA_FLAG_ACPI_SATA) | ||
925 | sata_acpi_set_state(ap, state); | ||
926 | else | ||
927 | pata_acpi_set_state(ap, state); | ||
882 | } | 928 | } |
883 | 929 | ||
884 | /** | 930 | /** |
@@ -974,57 +1020,6 @@ void ata_acpi_on_disable(struct ata_device *dev) | |||
974 | ata_acpi_clear_gtf(dev); | 1020 | ata_acpi_clear_gtf(dev); |
975 | } | 1021 | } |
976 | 1022 | ||
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) | 1023 | static void ata_acpi_register_power_resource(struct ata_device *dev) |
1029 | { | 1024 | { |
1030 | struct scsi_device *sdev = dev->sdev; | 1025 | struct scsi_device *sdev = dev->sdev; |
@@ -1047,13 +1042,13 @@ static void ata_acpi_unregister_power_resource(struct ata_device *dev) | |||
1047 | 1042 | ||
1048 | void ata_acpi_bind(struct ata_device *dev) | 1043 | void ata_acpi_bind(struct ata_device *dev) |
1049 | { | 1044 | { |
1050 | ata_acpi_add_pm_notifier(dev); | ||
1051 | ata_acpi_register_power_resource(dev); | 1045 | ata_acpi_register_power_resource(dev); |
1046 | if (zpodd_dev_enabled(dev)) | ||
1047 | dev_pm_qos_expose_flags(&dev->sdev->sdev_gendev, 0); | ||
1052 | } | 1048 | } |
1053 | 1049 | ||
1054 | void ata_acpi_unbind(struct ata_device *dev) | 1050 | void ata_acpi_unbind(struct ata_device *dev) |
1055 | { | 1051 | { |
1056 | ata_acpi_remove_pm_notifier(dev); | ||
1057 | ata_acpi_unregister_power_resource(dev); | 1052 | ata_acpi_unregister_power_resource(dev); |
1058 | } | 1053 | } |
1059 | 1054 | ||
@@ -1095,9 +1090,6 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev, | |||
1095 | acpi_handle *handle) | 1090 | acpi_handle *handle) |
1096 | { | 1091 | { |
1097 | struct ata_device *ata_dev; | 1092 | struct ata_device *ata_dev; |
1098 | acpi_status status; | ||
1099 | struct acpi_device *acpi_dev; | ||
1100 | struct acpi_device_power_state *states; | ||
1101 | 1093 | ||
1102 | if (ap->flags & ATA_FLAG_ACPI_SATA) { | 1094 | if (ap->flags & ATA_FLAG_ACPI_SATA) { |
1103 | if (!sata_pmp_attached(ap)) | 1095 | if (!sata_pmp_attached(ap)) |
@@ -1114,21 +1106,6 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev, | |||
1114 | if (!*handle) | 1106 | if (!*handle) |
1115 | return -ENODEV; | 1107 | return -ENODEV; |
1116 | 1108 | ||
1117 | status = acpi_bus_get_device(*handle, &acpi_dev); | ||
1118 | if (ACPI_FAILURE(status)) | ||
1119 | return 0; | ||
1120 | |||
1121 | /* | ||
1122 | * If firmware has _PS3 or _PR3 for this device, | ||
1123 | * and this ata ODD device support device attention, | ||
1124 | * it means this device can be powered off | ||
1125 | */ | ||
1126 | states = acpi_dev->power.states; | ||
1127 | if ((states[ACPI_STATE_D3_HOT].flags.valid || | ||
1128 | states[ACPI_STATE_D3_COLD].flags.explicit_set) && | ||
1129 | ata_dev->flags & ATA_DFLAG_DA) | ||
1130 | sdev->can_power_off = 1; | ||
1131 | |||
1132 | return 0; | 1109 | return 0; |
1133 | } | 1110 | } |
1134 | 1111 | ||