aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/libata.h
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-09-01 11:50:06 -0400
committerJeff Garzik <jgarzik@redhat.com>2010-10-21 20:21:04 -0400
commit6b7ae9545ad9875a289f4191c0216b473e313cb9 (patch)
tree216b4db276202d727ba134d256144a6670497180 /include/linux/libata.h
parent1152b2617a6e1943b6b82e07c962950e56f1000c (diff)
libata: reimplement link power management
The current LPM implementation has the following issues. * Operation order isn't well thought-out. e.g. HIPM should be configured after IPM in SControl is properly configured. Not the other way around. * Suspend/resume paths call ata_lpm_enable/disable() which must only be called from EH context directly. Also, ata_lpm_enable/disable() were called whether LPM was in use or not. * Implementation is per-port when it should be per-link. As a result, it can't be used for controllers with slave links or PMP. * LPM state isn't managed consistently. After a link reset for whatever reason including suspend/resume the actual LPM state would be reset leaving ap->lpm_policy inconsistent. * Generic/driver-specific logic boundary isn't clear. Currently, libahci has to mangle stuff which libata EH proper should be handling. This makes the implementation unnecessarily complex and fragile. * Tied to ALPM. Doesn't consider DIPM only cases and doesn't check whether the device allows HIPM. * Error handling isn't implemented. Given the extent of mismatch with the rest of libata, I don't think trying to fix it piecewise makes much sense. This patch reimplements LPM support. * The new implementation is per-link. The target policy is still port-wide (ap->target_lpm_policy) but all the mechanisms and states are per-link and integrate well with the rest of link abstraction and can work with slave and PMP links. * Core EH has proper control of LPM state. LPM state is reconfigured when and only when reconfiguration is necessary. It makes sure that LPM state is reset when probing for new device on the link. Controller agnostic logic is now implemented in libata EH proper and driver implementation only has to deal with controller specifics. * Proper error handling. LPM config failure is attributed to the device on the link and LPM is disabled for the link if it fails repeatedly. * ops->enable/disable_pm() are replaced with single ops->set_lpm() which takes @policy and @hints. This simplifies driver specific implementation. Signed-off-by: Tejun Heo <tj@kernel.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'include/linux/libata.h')
-rw-r--r--include/linux/libata.h17
1 files changed, 11 insertions, 6 deletions
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 7770eeb21039..bc4ee218b185 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -172,6 +172,7 @@ enum {
172 ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */ 172 ATA_LFLAG_NO_RETRY = (1 << 5), /* don't retry this link */
173 ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */ 173 ATA_LFLAG_DISABLED = (1 << 6), /* link is disabled */
174 ATA_LFLAG_SW_ACTIVITY = (1 << 7), /* keep activity stats */ 174 ATA_LFLAG_SW_ACTIVITY = (1 << 7), /* keep activity stats */
175 ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */
175 176
176 /* struct ata_port flags */ 177 /* struct ata_port flags */
177 ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ 178 ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */
@@ -324,12 +325,11 @@ enum {
324 ATA_EH_HARDRESET = (1 << 2), /* meaningful only in ->prereset */ 325 ATA_EH_HARDRESET = (1 << 2), /* meaningful only in ->prereset */
325 ATA_EH_RESET = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, 326 ATA_EH_RESET = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
326 ATA_EH_ENABLE_LINK = (1 << 3), 327 ATA_EH_ENABLE_LINK = (1 << 3),
327 ATA_EH_LPM = (1 << 4), /* link power management action */
328 ATA_EH_PARK = (1 << 5), /* unload heads and stop I/O */ 328 ATA_EH_PARK = (1 << 5), /* unload heads and stop I/O */
329 329
330 ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_PARK, 330 ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_PARK,
331 ATA_EH_ALL_ACTIONS = ATA_EH_REVALIDATE | ATA_EH_RESET | 331 ATA_EH_ALL_ACTIONS = ATA_EH_REVALIDATE | ATA_EH_RESET |
332 ATA_EH_ENABLE_LINK | ATA_EH_LPM, 332 ATA_EH_ENABLE_LINK,
333 333
334 /* ata_eh_info->flags */ 334 /* ata_eh_info->flags */
335 ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ 335 ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */
@@ -377,7 +377,6 @@ enum {
377 ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ 377 ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */
378 ATA_HORKAGE_DISABLE = (1 << 5), /* Disable it */ 378 ATA_HORKAGE_DISABLE = (1 << 5), /* Disable it */
379 ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ 379 ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */
380 ATA_HORKAGE_LPM = (1 << 7), /* Link PM problems */
381 ATA_HORKAGE_IVB = (1 << 8), /* cbl det validity bit bugs */ 380 ATA_HORKAGE_IVB = (1 << 8), /* cbl det validity bit bugs */
382 ATA_HORKAGE_STUCK_ERR = (1 << 9), /* stuck ERR on next PACKET */ 381 ATA_HORKAGE_STUCK_ERR = (1 << 9), /* stuck ERR on next PACKET */
383 ATA_HORKAGE_BRIDGE_OK = (1 << 10), /* no bridge limits */ 382 ATA_HORKAGE_BRIDGE_OK = (1 << 10), /* no bridge limits */
@@ -475,6 +474,11 @@ enum ata_lpm_policy {
475 ATA_LPM_MIN_POWER, 474 ATA_LPM_MIN_POWER,
476}; 475};
477 476
477enum ata_lpm_hints {
478 ATA_LPM_EMPTY = (1 << 0), /* port empty/probing */
479 ATA_LPM_HIPM = (1 << 1), /* may use HIPM */
480};
481
478/* forward declarations */ 482/* forward declarations */
479struct scsi_device; 483struct scsi_device;
480struct ata_port_operations; 484struct ata_port_operations;
@@ -702,6 +706,7 @@ struct ata_link {
702 unsigned int hw_sata_spd_limit; 706 unsigned int hw_sata_spd_limit;
703 unsigned int sata_spd_limit; 707 unsigned int sata_spd_limit;
704 unsigned int sata_spd; /* current SATA PHY speed */ 708 unsigned int sata_spd; /* current SATA PHY speed */
709 enum ata_lpm_policy lpm_policy;
705 710
706 /* record runtime error info, protected by host_set lock */ 711 /* record runtime error info, protected by host_set lock */
707 struct ata_eh_info eh_info; 712 struct ata_eh_info eh_info;
@@ -773,7 +778,7 @@ struct ata_port {
773 778
774 pm_message_t pm_mesg; 779 pm_message_t pm_mesg;
775 int *pm_result; 780 int *pm_result;
776 enum ata_lpm_policy lpm_policy; 781 enum ata_lpm_policy target_lpm_policy;
777 782
778 struct timer_list fastdrain_timer; 783 struct timer_list fastdrain_timer;
779 unsigned long fastdrain_cnt; 784 unsigned long fastdrain_cnt;
@@ -839,8 +844,8 @@ struct ata_port_operations {
839 int (*scr_write)(struct ata_link *link, unsigned int sc_reg, u32 val); 844 int (*scr_write)(struct ata_link *link, unsigned int sc_reg, u32 val);
840 void (*pmp_attach)(struct ata_port *ap); 845 void (*pmp_attach)(struct ata_port *ap);
841 void (*pmp_detach)(struct ata_port *ap); 846 void (*pmp_detach)(struct ata_port *ap);
842 int (*enable_pm)(struct ata_port *ap, enum ata_lpm_policy policy); 847 int (*set_lpm)(struct ata_link *link, enum ata_lpm_policy policy,
843 void (*disable_pm)(struct ata_port *ap); 848 unsigned hints);
844 849
845 /* 850 /*
846 * Start, stop, suspend and resume 851 * Start, stop, suspend and resume