diff options
-rw-r--r-- | drivers/ata/libata-acpi.c | 35 | ||||
-rw-r--r-- | drivers/ata/libata-eh.c | 2 | ||||
-rw-r--r-- | drivers/ata/libata-zpodd.c | 83 | ||||
-rw-r--r-- | drivers/ata/libata.h | 8 |
4 files changed, 118 insertions, 10 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 446b4e761af0..6f72c648ea14 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c | |||
@@ -835,6 +835,22 @@ void ata_acpi_on_resume(struct ata_port *ap) | |||
835 | } | 835 | } |
836 | } | 836 | } |
837 | 837 | ||
838 | static int ata_acpi_choose_suspend_state(struct ata_device *dev) | ||
839 | { | ||
840 | int d_max_in = ACPI_STATE_D3_COLD; | ||
841 | |||
842 | /* | ||
843 | * For ATAPI, runtime D3 cold is only allowed | ||
844 | * for ZPODD in zero power ready state | ||
845 | */ | ||
846 | if (dev->class == ATA_DEV_ATAPI && | ||
847 | !(zpodd_dev_enabled(dev) && zpodd_zpready(dev))) | ||
848 | d_max_in = ACPI_STATE_D3_HOT; | ||
849 | |||
850 | return acpi_pm_device_sleep_state(&dev->sdev->sdev_gendev, | ||
851 | NULL, d_max_in); | ||
852 | } | ||
853 | |||
838 | /** | 854 | /** |
839 | * ata_acpi_set_state - set the port power state | 855 | * ata_acpi_set_state - set the port power state |
840 | * @ap: target ATA port | 856 | * @ap: target ATA port |
@@ -861,17 +877,16 @@ void ata_acpi_set_state(struct ata_port *ap, pm_message_t state) | |||
861 | continue; | 877 | continue; |
862 | 878 | ||
863 | if (state.event != PM_EVENT_ON) { | 879 | if (state.event != PM_EVENT_ON) { |
864 | acpi_state = acpi_pm_device_sleep_state( | 880 | acpi_state = ata_acpi_choose_suspend_state(dev); |
865 | &dev->sdev->sdev_gendev, NULL, ACPI_STATE_D3); | 881 | if (acpi_state == ACPI_STATE_D0) |
866 | if (acpi_state > 0) | 882 | continue; |
867 | acpi_bus_set_power(handle, acpi_state); | 883 | if (zpodd_dev_enabled(dev) && |
868 | /* TBD: need to check if it's runtime pm request */ | 884 | acpi_state == ACPI_STATE_D3_COLD) |
869 | acpi_pm_device_run_wake( | 885 | zpodd_enable_run_wake(dev); |
870 | &dev->sdev->sdev_gendev, true); | 886 | acpi_bus_set_power(handle, acpi_state); |
871 | } else { | 887 | } else { |
872 | /* Ditto */ | 888 | if (zpodd_dev_enabled(dev)) |
873 | acpi_pm_device_run_wake( | 889 | zpodd_disable_run_wake(dev); |
874 | &dev->sdev->sdev_gendev, false); | ||
875 | acpi_bus_set_power(handle, ACPI_STATE_D0); | 890 | acpi_bus_set_power(handle, ACPI_STATE_D0); |
876 | } | 891 | } |
877 | } | 892 | } |
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index a0dddc3b4924..50f3ef04809d 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -3857,6 +3857,8 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
3857 | rc = atapi_eh_clear_ua(dev); | 3857 | rc = atapi_eh_clear_ua(dev); |
3858 | if (rc) | 3858 | if (rc) |
3859 | goto rest_fail; | 3859 | goto rest_fail; |
3860 | if (zpodd_dev_enabled(dev)) | ||
3861 | zpodd_post_poweron(dev); | ||
3860 | } | 3862 | } |
3861 | } | 3863 | } |
3862 | 3864 | ||
diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index 71dd48c94f2c..1f5d52ae3974 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c | |||
@@ -26,8 +26,26 @@ struct zpodd { | |||
26 | bool zp_ready; /* ZP ready state */ | 26 | bool zp_ready; /* ZP ready state */ |
27 | unsigned long last_ready; /* last ZP ready timestamp */ | 27 | unsigned long last_ready; /* last ZP ready timestamp */ |
28 | bool zp_sampled; /* ZP ready state sampled */ | 28 | bool zp_sampled; /* ZP ready state sampled */ |
29 | bool powered_off; /* ODD is powered off | ||
30 | * during suspend */ | ||
29 | }; | 31 | }; |
30 | 32 | ||
33 | static int eject_tray(struct ata_device *dev) | ||
34 | { | ||
35 | struct ata_taskfile tf = {}; | ||
36 | const char cdb[] = { GPCMD_START_STOP_UNIT, | ||
37 | 0, 0, 0, | ||
38 | 0x02, /* LoEj */ | ||
39 | 0, 0, 0, 0, 0, 0, 0, | ||
40 | }; | ||
41 | |||
42 | tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; | ||
43 | tf.command = ATA_CMD_PACKET; | ||
44 | tf.protocol = ATAPI_PROT_NODATA; | ||
45 | |||
46 | return ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0); | ||
47 | } | ||
48 | |||
31 | /* Per the spec, only slot type and drawer type ODD can be supported */ | 49 | /* Per the spec, only slot type and drawer type ODD can be supported */ |
32 | static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev) | 50 | static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev) |
33 | { | 51 | { |
@@ -149,6 +167,71 @@ void zpodd_on_suspend(struct ata_device *dev) | |||
149 | zpodd->zp_ready = true; | 167 | zpodd->zp_ready = true; |
150 | } | 168 | } |
151 | 169 | ||
170 | bool zpodd_zpready(struct ata_device *dev) | ||
171 | { | ||
172 | struct zpodd *zpodd = dev->zpodd; | ||
173 | return zpodd->zp_ready; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * Enable runtime wake capability through ACPI and set the powered_off flag, | ||
178 | * this flag will be used during resume to decide what operations are needed | ||
179 | * to take. | ||
180 | */ | ||
181 | void zpodd_enable_run_wake(struct ata_device *dev) | ||
182 | { | ||
183 | struct zpodd *zpodd = dev->zpodd; | ||
184 | |||
185 | zpodd->powered_off = true; | ||
186 | device_set_run_wake(&dev->sdev->sdev_gendev, true); | ||
187 | acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, true); | ||
188 | } | ||
189 | |||
190 | /* Disable runtime wake capability if it is enabled */ | ||
191 | void zpodd_disable_run_wake(struct ata_device *dev) | ||
192 | { | ||
193 | struct zpodd *zpodd = dev->zpodd; | ||
194 | |||
195 | if (zpodd->powered_off) { | ||
196 | acpi_pm_device_run_wake(&dev->sdev->sdev_gendev, false); | ||
197 | device_set_run_wake(&dev->sdev->sdev_gendev, false); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * Post power on processing after the ODD has been recovered. If the | ||
203 | * ODD wasn't powered off during suspend, it doesn't do anything. | ||
204 | * | ||
205 | * For drawer type ODD, if it is powered on due to user pressed the | ||
206 | * eject button, the tray needs to be ejected. This can only be done | ||
207 | * after the ODD has been recovered, i.e. link is initialized and | ||
208 | * device is able to process NON_DATA PIO command, as eject needs to | ||
209 | * send command for the ODD to process. | ||
210 | * | ||
211 | * The from_notify flag set in wake notification handler function | ||
212 | * zpodd_wake_dev represents if power on is due to user's action. | ||
213 | * | ||
214 | * For both types of ODD, several fields need to be reset. | ||
215 | */ | ||
216 | void zpodd_post_poweron(struct ata_device *dev) | ||
217 | { | ||
218 | struct zpodd *zpodd = dev->zpodd; | ||
219 | |||
220 | if (!zpodd->powered_off) | ||
221 | return; | ||
222 | |||
223 | zpodd->powered_off = false; | ||
224 | |||
225 | if (zpodd->from_notify) { | ||
226 | zpodd->from_notify = false; | ||
227 | if (zpodd->mech_type == ODD_MECH_TYPE_DRAWER) | ||
228 | eject_tray(dev); | ||
229 | } | ||
230 | |||
231 | zpodd->zp_sampled = false; | ||
232 | zpodd->zp_ready = false; | ||
233 | } | ||
234 | |||
152 | static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context) | 235 | static void zpodd_wake_dev(acpi_handle handle, u32 event, void *context) |
153 | { | 236 | { |
154 | struct ata_device *ata_dev = context; | 237 | struct ata_device *ata_dev = context; |
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index b9b2bb1d5dc6..c949dd311b2e 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h | |||
@@ -242,11 +242,19 @@ static inline bool zpodd_dev_enabled(struct ata_device *dev) | |||
242 | return dev->zpodd != NULL; | 242 | return dev->zpodd != NULL; |
243 | } | 243 | } |
244 | void zpodd_on_suspend(struct ata_device *dev); | 244 | void zpodd_on_suspend(struct ata_device *dev); |
245 | bool zpodd_zpready(struct ata_device *dev); | ||
246 | void zpodd_enable_run_wake(struct ata_device *dev); | ||
247 | void zpodd_disable_run_wake(struct ata_device *dev); | ||
248 | void zpodd_post_poweron(struct ata_device *dev); | ||
245 | #else /* CONFIG_SATA_ZPODD */ | 249 | #else /* CONFIG_SATA_ZPODD */ |
246 | static inline void zpodd_init(struct ata_device *dev) {} | 250 | static inline void zpodd_init(struct ata_device *dev) {} |
247 | static inline void zpodd_exit(struct ata_device *dev) {} | 251 | static inline void zpodd_exit(struct ata_device *dev) {} |
248 | static inline bool zpodd_dev_enabled(struct ata_device *dev) { return false; } | 252 | static inline bool zpodd_dev_enabled(struct ata_device *dev) { return false; } |
249 | static inline void zpodd_on_suspend(struct ata_device *dev) {} | 253 | static inline void zpodd_on_suspend(struct ata_device *dev) {} |
254 | static inline bool zpodd_zpready(struct ata_device *dev) { return false; } | ||
255 | static inline void zpodd_enable_run_wake(struct ata_device *dev) {} | ||
256 | static inline void zpodd_disable_run_wake(struct ata_device *dev) {} | ||
257 | static inline void zpodd_post_poweron(struct ata_device *dev) {} | ||
250 | #endif /* CONFIG_SATA_ZPODD */ | 258 | #endif /* CONFIG_SATA_ZPODD */ |
251 | 259 | ||
252 | #endif /* __LIBATA_H__ */ | 260 | #endif /* __LIBATA_H__ */ |