diff options
-rw-r--r-- | Documentation/scsi/link_power_management_policy.txt | 19 | ||||
-rw-r--r-- | drivers/ata/libata-core.c | 196 | ||||
-rw-r--r-- | drivers/ata/libata-eh.c | 4 | ||||
-rw-r--r-- | drivers/ata/libata-scsi.c | 68 | ||||
-rw-r--r-- | drivers/ata/libata.h | 2 | ||||
-rw-r--r-- | include/linux/ata.h | 21 | ||||
-rw-r--r-- | include/linux/libata.h | 21 |
7 files changed, 329 insertions, 2 deletions
diff --git a/Documentation/scsi/link_power_management_policy.txt b/Documentation/scsi/link_power_management_policy.txt new file mode 100644 index 000000000000..d18993d01884 --- /dev/null +++ b/Documentation/scsi/link_power_management_policy.txt | |||
@@ -0,0 +1,19 @@ | |||
1 | This parameter allows the user to set the link (interface) power management. | ||
2 | There are 3 possible options: | ||
3 | |||
4 | Value Effect | ||
5 | ---------------------------------------------------------------------------- | ||
6 | min_power Tell the controller to try to make the link use the | ||
7 | least possible power when possible. This may | ||
8 | sacrifice some performance due to increased latency | ||
9 | when coming out of lower power states. | ||
10 | |||
11 | max_performance Generally, this means no power management. Tell | ||
12 | the controller to have performance be a priority | ||
13 | over power management. | ||
14 | |||
15 | medium_power Tell the controller to enter a lower power state | ||
16 | when possible, but do not enter the lowest power | ||
17 | state, thus improving latency over min_power setting. | ||
18 | |||
19 | |||
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3891cdc6bd3d..513babe6a143 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -620,6 +620,177 @@ void ata_dev_disable(struct ata_device *dev) | |||
620 | } | 620 | } |
621 | } | 621 | } |
622 | 622 | ||
623 | static int ata_dev_set_dipm(struct ata_device *dev, enum link_pm policy) | ||
624 | { | ||
625 | struct ata_link *link = dev->link; | ||
626 | struct ata_port *ap = link->ap; | ||
627 | u32 scontrol; | ||
628 | unsigned int err_mask; | ||
629 | int rc; | ||
630 | |||
631 | /* | ||
632 | * disallow DIPM for drivers which haven't set | ||
633 | * ATA_FLAG_IPM. This is because when DIPM is enabled, | ||
634 | * phy ready will be set in the interrupt status on | ||
635 | * state changes, which will cause some drivers to | ||
636 | * think there are errors - additionally drivers will | ||
637 | * need to disable hot plug. | ||
638 | */ | ||
639 | if (!(ap->flags & ATA_FLAG_IPM) || !ata_dev_enabled(dev)) { | ||
640 | ap->pm_policy = NOT_AVAILABLE; | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | |||
644 | /* | ||
645 | * For DIPM, we will only enable it for the | ||
646 | * min_power setting. | ||
647 | * | ||
648 | * Why? Because Disks are too stupid to know that | ||
649 | * If the host rejects a request to go to SLUMBER | ||
650 | * they should retry at PARTIAL, and instead it | ||
651 | * just would give up. So, for medium_power to | ||
652 | * work at all, we need to only allow HIPM. | ||
653 | */ | ||
654 | rc = sata_scr_read(link, SCR_CONTROL, &scontrol); | ||
655 | if (rc) | ||
656 | return rc; | ||
657 | |||
658 | switch (policy) { | ||
659 | case MIN_POWER: | ||
660 | /* no restrictions on IPM transitions */ | ||
661 | scontrol &= ~(0x3 << 8); | ||
662 | rc = sata_scr_write(link, SCR_CONTROL, scontrol); | ||
663 | if (rc) | ||
664 | return rc; | ||
665 | |||
666 | /* enable DIPM */ | ||
667 | if (dev->flags & ATA_DFLAG_DIPM) | ||
668 | err_mask = ata_dev_set_feature(dev, | ||
669 | SETFEATURES_SATA_ENABLE, SATA_DIPM); | ||
670 | break; | ||
671 | case MEDIUM_POWER: | ||
672 | /* allow IPM to PARTIAL */ | ||
673 | scontrol &= ~(0x1 << 8); | ||
674 | scontrol |= (0x2 << 8); | ||
675 | rc = sata_scr_write(link, SCR_CONTROL, scontrol); | ||
676 | if (rc) | ||
677 | return rc; | ||
678 | |||
679 | /* disable DIPM */ | ||
680 | if (ata_dev_enabled(dev) && (dev->flags & ATA_DFLAG_DIPM)) | ||
681 | err_mask = ata_dev_set_feature(dev, | ||
682 | SETFEATURES_SATA_DISABLE, SATA_DIPM); | ||
683 | break; | ||
684 | case NOT_AVAILABLE: | ||
685 | case MAX_PERFORMANCE: | ||
686 | /* disable all IPM transitions */ | ||
687 | scontrol |= (0x3 << 8); | ||
688 | rc = sata_scr_write(link, SCR_CONTROL, scontrol); | ||
689 | if (rc) | ||
690 | return rc; | ||
691 | |||
692 | /* disable DIPM */ | ||
693 | if (ata_dev_enabled(dev) && (dev->flags & ATA_DFLAG_DIPM)) | ||
694 | err_mask = ata_dev_set_feature(dev, | ||
695 | SETFEATURES_SATA_DISABLE, SATA_DIPM); | ||
696 | break; | ||
697 | } | ||
698 | |||
699 | /* FIXME: handle SET FEATURES failure */ | ||
700 | (void) err_mask; | ||
701 | |||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | /** | ||
706 | * ata_dev_enable_pm - enable SATA interface power management | ||
707 | * @device - device to enable ipm for | ||
708 | * @policy - the link power management policy | ||
709 | * | ||
710 | * Enable SATA Interface power management. This will enable | ||
711 | * Device Interface Power Management (DIPM) for min_power | ||
712 | * policy, and then call driver specific callbacks for | ||
713 | * enabling Host Initiated Power management. | ||
714 | * | ||
715 | * Locking: Caller. | ||
716 | * Returns: -EINVAL if IPM is not supported, 0 otherwise. | ||
717 | */ | ||
718 | void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy) | ||
719 | { | ||
720 | int rc = 0; | ||
721 | struct ata_port *ap = dev->link->ap; | ||
722 | |||
723 | /* set HIPM first, then DIPM */ | ||
724 | if (ap->ops->enable_pm) | ||
725 | rc = ap->ops->enable_pm(ap, policy); | ||
726 | if (rc) | ||
727 | goto enable_pm_out; | ||
728 | rc = ata_dev_set_dipm(dev, policy); | ||
729 | |||
730 | enable_pm_out: | ||
731 | if (rc) | ||
732 | ap->pm_policy = MAX_PERFORMANCE; | ||
733 | else | ||
734 | ap->pm_policy = policy; | ||
735 | return /* rc */; /* hopefully we can use 'rc' eventually */ | ||
736 | } | ||
737 | |||
738 | /** | ||
739 | * ata_dev_disable_pm - disable SATA interface power management | ||
740 | * @device - device to enable ipm for | ||
741 | * | ||
742 | * Disable SATA Interface power management. This will disable | ||
743 | * Device Interface Power Management (DIPM) without changing | ||
744 | * policy, call driver specific callbacks for disabling Host | ||
745 | * Initiated Power management. | ||
746 | * | ||
747 | * Locking: Caller. | ||
748 | * Returns: void | ||
749 | */ | ||
750 | static void ata_dev_disable_pm(struct ata_device *dev) | ||
751 | { | ||
752 | struct ata_port *ap = dev->link->ap; | ||
753 | |||
754 | ata_dev_set_dipm(dev, MAX_PERFORMANCE); | ||
755 | if (ap->ops->disable_pm) | ||
756 | ap->ops->disable_pm(ap); | ||
757 | } | ||
758 | |||
759 | void ata_lpm_schedule(struct ata_port *ap, enum link_pm policy) | ||
760 | { | ||
761 | ap->pm_policy = policy; | ||
762 | ap->link.eh_info.action |= ATA_EHI_LPM; | ||
763 | ap->link.eh_info.flags |= ATA_EHI_NO_AUTOPSY; | ||
764 | ata_port_schedule_eh(ap); | ||
765 | } | ||
766 | |||
767 | static void ata_lpm_enable(struct ata_host *host) | ||
768 | { | ||
769 | struct ata_link *link; | ||
770 | struct ata_port *ap; | ||
771 | struct ata_device *dev; | ||
772 | int i; | ||
773 | |||
774 | for (i = 0; i < host->n_ports; i++) { | ||
775 | ap = host->ports[i]; | ||
776 | ata_port_for_each_link(link, ap) { | ||
777 | ata_link_for_each_dev(dev, link) | ||
778 | ata_dev_disable_pm(dev); | ||
779 | } | ||
780 | } | ||
781 | } | ||
782 | |||
783 | static void ata_lpm_disable(struct ata_host *host) | ||
784 | { | ||
785 | int i; | ||
786 | |||
787 | for (i = 0; i < host->n_ports; i++) { | ||
788 | struct ata_port *ap = host->ports[i]; | ||
789 | ata_lpm_schedule(ap, ap->pm_policy); | ||
790 | } | ||
791 | } | ||
792 | |||
793 | |||
623 | /** | 794 | /** |
624 | * ata_devchk - PATA device presence detection | 795 | * ata_devchk - PATA device presence detection |
625 | * @ap: ATA channel to examine | 796 | * @ap: ATA channel to examine |
@@ -2101,6 +2272,13 @@ int ata_dev_configure(struct ata_device *dev) | |||
2101 | if (dev->flags & ATA_DFLAG_LBA48) | 2272 | if (dev->flags & ATA_DFLAG_LBA48) |
2102 | dev->max_sectors = ATA_MAX_SECTORS_LBA48; | 2273 | dev->max_sectors = ATA_MAX_SECTORS_LBA48; |
2103 | 2274 | ||
2275 | if (!(dev->horkage & ATA_HORKAGE_IPM)) { | ||
2276 | if (ata_id_has_hipm(dev->id)) | ||
2277 | dev->flags |= ATA_DFLAG_HIPM; | ||
2278 | if (ata_id_has_dipm(dev->id)) | ||
2279 | dev->flags |= ATA_DFLAG_DIPM; | ||
2280 | } | ||
2281 | |||
2104 | if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { | 2282 | if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { |
2105 | /* Let the user know. We don't want to disallow opens for | 2283 | /* Let the user know. We don't want to disallow opens for |
2106 | rescue purposes, or in case the vendor is just a blithering | 2284 | rescue purposes, or in case the vendor is just a blithering |
@@ -2126,6 +2304,13 @@ int ata_dev_configure(struct ata_device *dev) | |||
2126 | dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128, | 2304 | dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128, |
2127 | dev->max_sectors); | 2305 | dev->max_sectors); |
2128 | 2306 | ||
2307 | if (ata_dev_blacklisted(dev) & ATA_HORKAGE_IPM) { | ||
2308 | dev->horkage |= ATA_HORKAGE_IPM; | ||
2309 | |||
2310 | /* reset link pm_policy for this port to no pm */ | ||
2311 | ap->pm_policy = MAX_PERFORMANCE; | ||
2312 | } | ||
2313 | |||
2129 | if (ap->ops->dev_config) | 2314 | if (ap->ops->dev_config) |
2130 | ap->ops->dev_config(dev); | 2315 | ap->ops->dev_config(dev); |
2131 | 2316 | ||
@@ -6361,6 +6546,12 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg) | |||
6361 | { | 6546 | { |
6362 | int rc; | 6547 | int rc; |
6363 | 6548 | ||
6549 | /* | ||
6550 | * disable link pm on all ports before requesting | ||
6551 | * any pm activity | ||
6552 | */ | ||
6553 | ata_lpm_enable(host); | ||
6554 | |||
6364 | rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1); | 6555 | rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1); |
6365 | if (rc == 0) | 6556 | if (rc == 0) |
6366 | host->dev->power.power_state = mesg; | 6557 | host->dev->power.power_state = mesg; |
@@ -6383,6 +6574,9 @@ void ata_host_resume(struct ata_host *host) | |||
6383 | ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET, | 6574 | ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET, |
6384 | ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0); | 6575 | ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0); |
6385 | host->dev->power.power_state = PMSG_ON; | 6576 | host->dev->power.power_state = PMSG_ON; |
6577 | |||
6578 | /* reenable link pm */ | ||
6579 | ata_lpm_disable(host); | ||
6386 | } | 6580 | } |
6387 | #endif | 6581 | #endif |
6388 | 6582 | ||
@@ -6925,6 +7119,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) | |||
6925 | struct ata_port *ap = host->ports[i]; | 7119 | struct ata_port *ap = host->ports[i]; |
6926 | 7120 | ||
6927 | ata_scsi_scan_host(ap, 1); | 7121 | ata_scsi_scan_host(ap, 1); |
7122 | ata_lpm_schedule(ap, ap->pm_policy); | ||
6928 | } | 7123 | } |
6929 | 7124 | ||
6930 | return 0; | 7125 | return 0; |
@@ -7321,7 +7516,6 @@ const struct ata_port_info ata_dummy_port_info = { | |||
7321 | * likely to change as new drivers are added and updated. | 7516 | * likely to change as new drivers are added and updated. |
7322 | * Do not depend on ABI/API stability. | 7517 | * Do not depend on ABI/API stability. |
7323 | */ | 7518 | */ |
7324 | |||
7325 | EXPORT_SYMBOL_GPL(sata_deb_timing_normal); | 7519 | EXPORT_SYMBOL_GPL(sata_deb_timing_normal); |
7326 | EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); | 7520 | EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); |
7327 | EXPORT_SYMBOL_GPL(sata_deb_timing_long); | 7521 | EXPORT_SYMBOL_GPL(sata_deb_timing_long); |
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index ec55d63cf20e..fefea7470e51 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c | |||
@@ -2628,6 +2628,10 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, | |||
2628 | ehc->i.flags &= ~ATA_EHI_SETMODE; | 2628 | ehc->i.flags &= ~ATA_EHI_SETMODE; |
2629 | } | 2629 | } |
2630 | 2630 | ||
2631 | if (ehc->i.action & ATA_EHI_LPM) | ||
2632 | ata_link_for_each_dev(dev, link) | ||
2633 | ata_dev_enable_pm(dev, ap->pm_policy); | ||
2634 | |||
2631 | /* this link is okay now */ | 2635 | /* this link is okay now */ |
2632 | ehc->i.flags = 0; | 2636 | ehc->i.flags = 0; |
2633 | continue; | 2637 | continue; |
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index f752eddc19ed..93bd36c19690 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -110,6 +110,74 @@ static struct scsi_transport_template ata_scsi_transport_template = { | |||
110 | }; | 110 | }; |
111 | 111 | ||
112 | 112 | ||
113 | static const struct { | ||
114 | enum link_pm value; | ||
115 | const char *name; | ||
116 | } link_pm_policy[] = { | ||
117 | { NOT_AVAILABLE, "max_performance" }, | ||
118 | { MIN_POWER, "min_power" }, | ||
119 | { MAX_PERFORMANCE, "max_performance" }, | ||
120 | { MEDIUM_POWER, "medium_power" }, | ||
121 | }; | ||
122 | |||
123 | const char *ata_scsi_lpm_get(enum link_pm policy) | ||
124 | { | ||
125 | int i; | ||
126 | |||
127 | for (i = 0; i < ARRAY_SIZE(link_pm_policy); i++) | ||
128 | if (link_pm_policy[i].value == policy) | ||
129 | return link_pm_policy[i].name; | ||
130 | |||
131 | return NULL; | ||
132 | } | ||
133 | |||
134 | static ssize_t ata_scsi_lpm_put(struct class_device *class_dev, | ||
135 | const char *buf, size_t count) | ||
136 | { | ||
137 | struct Scsi_Host *shost = class_to_shost(class_dev); | ||
138 | struct ata_port *ap = ata_shost_to_port(shost); | ||
139 | enum link_pm policy = 0; | ||
140 | int i; | ||
141 | |||
142 | /* | ||
143 | * we are skipping array location 0 on purpose - this | ||
144 | * is because a value of NOT_AVAILABLE is displayed | ||
145 | * to the user as max_performance, but when the user | ||
146 | * writes "max_performance", they actually want the | ||
147 | * value to match MAX_PERFORMANCE. | ||
148 | */ | ||
149 | for (i = 1; i < ARRAY_SIZE(link_pm_policy); i++) { | ||
150 | const int len = strlen(link_pm_policy[i].name); | ||
151 | if (strncmp(link_pm_policy[i].name, buf, len) == 0 && | ||
152 | buf[len] == '\n') { | ||
153 | policy = link_pm_policy[i].value; | ||
154 | break; | ||
155 | } | ||
156 | } | ||
157 | if (!policy) | ||
158 | return -EINVAL; | ||
159 | |||
160 | ata_lpm_schedule(ap, policy); | ||
161 | return count; | ||
162 | } | ||
163 | |||
164 | static ssize_t | ||
165 | ata_scsi_lpm_show(struct class_device *class_dev, char *buf) | ||
166 | { | ||
167 | struct Scsi_Host *shost = class_to_shost(class_dev); | ||
168 | struct ata_port *ap = ata_shost_to_port(shost); | ||
169 | const char *policy = | ||
170 | ata_scsi_lpm_get(ap->pm_policy); | ||
171 | |||
172 | if (!policy) | ||
173 | return -EINVAL; | ||
174 | |||
175 | return snprintf(buf, 23, "%s\n", policy); | ||
176 | } | ||
177 | CLASS_DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR, | ||
178 | ata_scsi_lpm_show, ata_scsi_lpm_put); | ||
179 | EXPORT_SYMBOL_GPL(class_device_attr_link_power_management_policy); | ||
180 | |||
113 | static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, | 181 | static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, |
114 | void (*done)(struct scsi_cmnd *)) | 182 | void (*done)(struct scsi_cmnd *)) |
115 | { | 183 | { |
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 90df58a3edc9..0e6cf3a484dc 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h | |||
@@ -101,6 +101,8 @@ extern int sata_link_init_spd(struct ata_link *link); | |||
101 | extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); | 101 | extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); |
102 | extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); | 102 | extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); |
103 | extern struct ata_port *ata_port_alloc(struct ata_host *host); | 103 | extern struct ata_port *ata_port_alloc(struct ata_host *host); |
104 | extern void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy); | ||
105 | extern void ata_lpm_schedule(struct ata_port *ap, enum link_pm); | ||
104 | 106 | ||
105 | /* libata-acpi.c */ | 107 | /* libata-acpi.c */ |
106 | #ifdef CONFIG_ATA_ACPI | 108 | #ifdef CONFIG_ATA_ACPI |
diff --git a/include/linux/ata.h b/include/linux/ata.h index e21c002c3a4a..128dc7ad4901 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h | |||
@@ -236,6 +236,7 @@ enum { | |||
236 | 236 | ||
237 | /* SETFEATURE Sector counts for SATA features */ | 237 | /* SETFEATURE Sector counts for SATA features */ |
238 | SATA_AN = 0x05, /* Asynchronous Notification */ | 238 | SATA_AN = 0x05, /* Asynchronous Notification */ |
239 | SATA_DIPM = 0x03, /* Device Initiated Power Management */ | ||
239 | 240 | ||
240 | /* ATAPI stuff */ | 241 | /* ATAPI stuff */ |
241 | ATAPI_PKT_DMA = (1 << 0), | 242 | ATAPI_PKT_DMA = (1 << 0), |
@@ -378,6 +379,26 @@ struct ata_taskfile { | |||
378 | 379 | ||
379 | #define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20) | 380 | #define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20) |
380 | 381 | ||
382 | static inline bool ata_id_has_hipm(const u16 *id) | ||
383 | { | ||
384 | u16 val = id[76]; | ||
385 | |||
386 | if (val == 0 || val == 0xffff) | ||
387 | return false; | ||
388 | |||
389 | return val & (1 << 9); | ||
390 | } | ||
391 | |||
392 | static inline bool ata_id_has_dipm(const u16 *id) | ||
393 | { | ||
394 | u16 val = id[78]; | ||
395 | |||
396 | if (val == 0 || val == 0xffff) | ||
397 | return false; | ||
398 | |||
399 | return val & (1 << 3); | ||
400 | } | ||
401 | |||
381 | static inline int ata_id_has_fua(const u16 *id) | 402 | static inline int ata_id_has_fua(const u16 *id) |
382 | { | 403 | { |
383 | if ((id[84] & 0xC000) != 0x4000) | 404 | if ((id[84] & 0xC000) != 0x4000) |
diff --git a/include/linux/libata.h b/include/linux/libata.h index 439d40f86c55..147ccc40c8af 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
@@ -133,6 +133,8 @@ enum { | |||
133 | ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ | 133 | ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ |
134 | ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ | 134 | ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ |
135 | ATA_DFLAG_AN = (1 << 7), /* AN configured */ | 135 | ATA_DFLAG_AN = (1 << 7), /* AN configured */ |
136 | ATA_DFLAG_HIPM = (1 << 8), /* device supports HIPM */ | ||
137 | ATA_DFLAG_DIPM = (1 << 9), /* device supports DIPM */ | ||
136 | ATA_DFLAG_CFG_MASK = (1 << 12) - 1, | 138 | ATA_DFLAG_CFG_MASK = (1 << 12) - 1, |
137 | 139 | ||
138 | ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */ | 140 | ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */ |
@@ -186,6 +188,7 @@ enum { | |||
186 | ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */ | 188 | ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */ |
187 | ATA_FLAG_AN = (1 << 18), /* controller supports AN */ | 189 | ATA_FLAG_AN = (1 << 18), /* controller supports AN */ |
188 | ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */ | 190 | ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */ |
191 | ATA_FLAG_IPM = (1 << 20), /* driver can handle IPM */ | ||
189 | 192 | ||
190 | /* The following flag belongs to ap->pflags but is kept in | 193 | /* The following flag belongs to ap->pflags but is kept in |
191 | * ap->flags because it's referenced in many LLDs and will be | 194 | * ap->flags because it's referenced in many LLDs and will be |
@@ -302,6 +305,7 @@ enum { | |||
302 | ATA_EHI_RESUME_LINK = (1 << 1), /* resume link (reset modifier) */ | 305 | ATA_EHI_RESUME_LINK = (1 << 1), /* resume link (reset modifier) */ |
303 | ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ | 306 | ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ |
304 | ATA_EHI_QUIET = (1 << 3), /* be quiet */ | 307 | ATA_EHI_QUIET = (1 << 3), /* be quiet */ |
308 | ATA_EHI_LPM = (1 << 4), /* link power management action */ | ||
305 | 309 | ||
306 | ATA_EHI_DID_SOFTRESET = (1 << 16), /* already soft-reset this port */ | 310 | ATA_EHI_DID_SOFTRESET = (1 << 16), /* already soft-reset this port */ |
307 | ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */ | 311 | ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */ |
@@ -333,6 +337,7 @@ enum { | |||
333 | ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ | 337 | ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ |
334 | ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ | 338 | ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ |
335 | ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ | 339 | ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ |
340 | ATA_HORKAGE_IPM = (1 << 7), /* Link PM problems */ | ||
336 | 341 | ||
337 | /* DMA mask for user DMA control: User visible values; DO NOT | 342 | /* DMA mask for user DMA control: User visible values; DO NOT |
338 | renumber */ | 343 | renumber */ |
@@ -378,6 +383,18 @@ typedef int (*ata_reset_fn_t)(struct ata_link *link, unsigned int *classes, | |||
378 | unsigned long deadline); | 383 | unsigned long deadline); |
379 | typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes); | 384 | typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes); |
380 | 385 | ||
386 | /* | ||
387 | * host pm policy: If you alter this, you also need to alter libata-scsi.c | ||
388 | * (for the ascii descriptions) | ||
389 | */ | ||
390 | enum link_pm { | ||
391 | NOT_AVAILABLE, | ||
392 | MIN_POWER, | ||
393 | MAX_PERFORMANCE, | ||
394 | MEDIUM_POWER, | ||
395 | }; | ||
396 | extern struct class_device_attribute class_device_attr_link_power_management_policy; | ||
397 | |||
381 | struct ata_ioports { | 398 | struct ata_ioports { |
382 | void __iomem *cmd_addr; | 399 | void __iomem *cmd_addr; |
383 | void __iomem *data_addr; | 400 | void __iomem *data_addr; |
@@ -624,6 +641,7 @@ struct ata_port { | |||
624 | 641 | ||
625 | pm_message_t pm_mesg; | 642 | pm_message_t pm_mesg; |
626 | int *pm_result; | 643 | int *pm_result; |
644 | enum link_pm pm_policy; | ||
627 | 645 | ||
628 | struct timer_list fastdrain_timer; | 646 | struct timer_list fastdrain_timer; |
629 | unsigned long fastdrain_cnt; | 647 | unsigned long fastdrain_cnt; |
@@ -691,7 +709,8 @@ struct ata_port_operations { | |||
691 | 709 | ||
692 | int (*port_suspend) (struct ata_port *ap, pm_message_t mesg); | 710 | int (*port_suspend) (struct ata_port *ap, pm_message_t mesg); |
693 | int (*port_resume) (struct ata_port *ap); | 711 | int (*port_resume) (struct ata_port *ap); |
694 | 712 | int (*enable_pm) (struct ata_port *ap, enum link_pm policy); | |
713 | void (*disable_pm) (struct ata_port *ap); | ||
695 | int (*port_start) (struct ata_port *ap); | 714 | int (*port_start) (struct ata_port *ap); |
696 | void (*port_stop) (struct ata_port *ap); | 715 | void (*port_stop) (struct ata_port *ap); |
697 | 716 | ||