Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[libata] Link power management infrastructure

Device Initiated Power Management, which is defined
in SATA 2.5 can be enabled for disks which support it.
This patch enables DIPM when the user sets the link
power management policy to "min_power".

Additionally, libata drivers can define a function
(enable_pm) that will perform hardware specific actions to
enable whatever power management policy the user set up
for Host Initiated Power management (HIPM).
This power management policy will be activated after all
disks have been enumerated and intialized. Drivers should
also define disable_pm, which will turn off link power
management, but not change link power management policy.

Documentation/scsi/link_power_management_policy.txt has additional
information.

Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>

authored by

Kristen Carlson Accardi and committed by
Jeff Garzik
ca77329f ab6fc95f

+329 -2
+195 -1
drivers/ata/libata-core.c
··· 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 795 * ata_devchk - PATA device presence detection 625 796 * @ap: ATA channel to examine ··· 2272 2101 if (dev->flags & ATA_DFLAG_LBA48) 2273 2102 dev->max_sectors = ATA_MAX_SECTORS_LBA48; 2274 2103 2104 + if (!(dev->horkage & ATA_HORKAGE_IPM)) { 2105 + if (ata_id_has_hipm(dev->id)) 2106 + dev->flags |= ATA_DFLAG_HIPM; 2107 + if (ata_id_has_dipm(dev->id)) 2108 + dev->flags |= ATA_DFLAG_DIPM; 2109 + } 2110 + 2275 2111 if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { 2276 2112 /* Let the user know. We don't want to disallow opens for 2277 2113 rescue purposes, or in case the vendor is just a blithering ··· 2303 2125 if (dev->horkage & ATA_HORKAGE_MAX_SEC_128) 2304 2126 dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128, 2305 2127 dev->max_sectors); 2128 + 2129 + if (ata_dev_blacklisted(dev) & ATA_HORKAGE_IPM) { 2130 + dev->horkage |= ATA_HORKAGE_IPM; 2131 + 2132 + /* reset link pm_policy for this port to no pm */ 2133 + ap->pm_policy = MAX_PERFORMANCE; 2134 + } 2306 2135 2307 2136 if (ap->ops->dev_config) 2308 2137 ap->ops->dev_config(dev); ··· 6546 6361 { 6547 6362 int rc; 6548 6363 6364 + /* 6365 + * disable link pm on all ports before requesting 6366 + * any pm activity 6367 + */ 6368 + ata_lpm_enable(host); 6369 + 6549 6370 rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1); 6550 6371 if (rc == 0) 6551 6372 host->dev->power.power_state = mesg; ··· 6574 6383 ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET, 6575 6384 ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0); 6576 6385 host->dev->power.power_state = PMSG_ON; 6386 + 6387 + /* reenable link pm */ 6388 + ata_lpm_disable(host); 6577 6389 } 6578 6390 #endif 6579 6391 ··· 7119 6925 struct ata_port *ap = host->ports[i]; 7120 6926 7121 6927 ata_scsi_scan_host(ap, 1); 6928 + ata_lpm_schedule(ap, ap->pm_policy); 7122 6929 } 7123 6930 7124 6931 return 0; ··· 7516 7321 * likely to change as new drivers are added and updated. 7517 7322 * Do not depend on ABI/API stability. 7518 7323 */ 7519 - 7520 7324 EXPORT_SYMBOL_GPL(sata_deb_timing_normal); 7521 7325 EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); 7522 7326 EXPORT_SYMBOL_GPL(sata_deb_timing_long);
+4
drivers/ata/libata-eh.c
··· 2628 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 2635 /* this link is okay now */ 2632 2636 ehc->i.flags = 0; 2633 2637 continue;
+68
drivers/ata/libata-scsi.c
··· 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 181 static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, 114 182 void (*done)(struct scsi_cmnd *)) 115 183 {
+2
drivers/ata/libata.h
··· 101 101 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); 102 102 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); 103 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 107 /* libata-acpi.c */ 106 108 #ifdef CONFIG_ATA_ACPI
+21
include/linux/ata.h
··· 236 236 237 237 /* SETFEATURE Sector counts for SATA features */ 238 238 SATA_AN = 0x05, /* Asynchronous Notification */ 239 + SATA_DIPM = 0x03, /* Device Initiated Power Management */ 239 240 240 241 /* ATAPI stuff */ 241 242 ATAPI_PKT_DMA = (1 << 0), ··· 378 377 ((u64) (id)[(n) + 0]) ) 379 378 380 379 #define ata_id_cdb_intr(id) (((id)[0] & 0x60) == 0x20) 380 + 381 + static inline bool ata_id_has_hipm(const u16 *id) 382 + { 383 + u16 val = id[76]; 384 + 385 + if (val == 0 || val == 0xffff) 386 + return false; 387 + 388 + return val & (1 << 9); 389 + } 390 + 391 + static inline bool ata_id_has_dipm(const u16 *id) 392 + { 393 + u16 val = id[78]; 394 + 395 + if (val == 0 || val == 0xffff) 396 + return false; 397 + 398 + return val & (1 << 3); 399 + } 381 400 382 401 static inline int ata_id_has_fua(const u16 *id) 383 402 {
+20 -1
include/linux/libata.h
··· 133 133 ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ 134 134 ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ 135 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 138 ATA_DFLAG_CFG_MASK = (1 << 12) - 1, 137 139 138 140 ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */ ··· 188 186 ATA_FLAG_ACPI_SATA = (1 << 17), /* need native SATA ACPI layout */ 189 187 ATA_FLAG_AN = (1 << 18), /* controller supports AN */ 190 188 ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */ 189 + ATA_FLAG_IPM = (1 << 20), /* driver can handle IPM */ 191 190 192 191 /* The following flag belongs to ap->pflags but is kept in 193 192 * ap->flags because it's referenced in many LLDs and will be ··· 305 302 ATA_EHI_RESUME_LINK = (1 << 1), /* resume link (reset modifier) */ 306 303 ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */ 307 304 ATA_EHI_QUIET = (1 << 3), /* be quiet */ 305 + ATA_EHI_LPM = (1 << 4), /* link power management action */ 308 306 309 307 ATA_EHI_DID_SOFTRESET = (1 << 16), /* already soft-reset this port */ 310 308 ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */ ··· 337 333 ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */ 338 334 ATA_HORKAGE_SKIP_PM = (1 << 5), /* Skip PM operations */ 339 335 ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */ 336 + ATA_HORKAGE_IPM = (1 << 7), /* Link PM problems */ 340 337 341 338 /* DMA mask for user DMA control: User visible values; DO NOT 342 339 renumber */ ··· 382 377 typedef int (*ata_reset_fn_t)(struct ata_link *link, unsigned int *classes, 383 378 unsigned long deadline); 384 379 typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes); 380 + 381 + /* 382 + * host pm policy: If you alter this, you also need to alter libata-scsi.c 383 + * (for the ascii descriptions) 384 + */ 385 + enum link_pm { 386 + NOT_AVAILABLE, 387 + MIN_POWER, 388 + MAX_PERFORMANCE, 389 + MEDIUM_POWER, 390 + }; 391 + extern struct class_device_attribute class_device_attr_link_power_management_policy; 385 392 386 393 struct ata_ioports { 387 394 void __iomem *cmd_addr; ··· 641 624 642 625 pm_message_t pm_mesg; 643 626 int *pm_result; 627 + enum link_pm pm_policy; 644 628 645 629 struct timer_list fastdrain_timer; 646 630 unsigned long fastdrain_cnt; ··· 709 691 710 692 int (*port_suspend) (struct ata_port *ap, pm_message_t mesg); 711 693 int (*port_resume) (struct ata_port *ap); 712 - 694 + int (*enable_pm) (struct ata_port *ap, enum link_pm policy); 695 + void (*disable_pm) (struct ata_port *ap); 713 696 int (*port_start) (struct ata_port *ap); 714 697 void (*port_stop) (struct ata_port *ap); 715 698