diff options
| -rw-r--r-- | Documentation/scsi/link_power_management_policy.txt | 19 | ||||
| -rw-r--r-- | drivers/ata/ahci.c | 157 | ||||
| -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 |
8 files changed, 484 insertions, 4 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/ahci.c b/drivers/ata/ahci.c index c8ab947cf359..ed9b407e42d4 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
| @@ -49,6 +49,9 @@ | |||
| 49 | #define DRV_NAME "ahci" | 49 | #define DRV_NAME "ahci" |
| 50 | #define DRV_VERSION "3.0" | 50 | #define DRV_VERSION "3.0" |
| 51 | 51 | ||
| 52 | static int ahci_enable_alpm(struct ata_port *ap, | ||
| 53 | enum link_pm policy); | ||
| 54 | static void ahci_disable_alpm(struct ata_port *ap); | ||
| 52 | 55 | ||
| 53 | enum { | 56 | enum { |
| 54 | AHCI_PCI_BAR = 5, | 57 | AHCI_PCI_BAR = 5, |
| @@ -99,6 +102,7 @@ enum { | |||
| 99 | HOST_CAP_SSC = (1 << 14), /* Slumber capable */ | 102 | HOST_CAP_SSC = (1 << 14), /* Slumber capable */ |
| 100 | HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ | 103 | HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */ |
| 101 | HOST_CAP_CLO = (1 << 24), /* Command List Override support */ | 104 | HOST_CAP_CLO = (1 << 24), /* Command List Override support */ |
| 105 | HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */ | ||
| 102 | HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ | 106 | HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */ |
| 103 | HOST_CAP_SNTF = (1 << 29), /* SNotification register */ | 107 | HOST_CAP_SNTF = (1 << 29), /* SNotification register */ |
| 104 | HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ | 108 | HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */ |
| @@ -155,6 +159,8 @@ enum { | |||
| 155 | PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, | 159 | PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, |
| 156 | 160 | ||
| 157 | /* PORT_CMD bits */ | 161 | /* PORT_CMD bits */ |
| 162 | PORT_CMD_ASP = (1 << 27), /* Aggressive Slumber/Partial */ | ||
| 163 | PORT_CMD_ALPE = (1 << 26), /* Aggressive Link PM enable */ | ||
| 158 | PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ | 164 | PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ |
| 159 | PORT_CMD_PMP = (1 << 17), /* PMP attached */ | 165 | PORT_CMD_PMP = (1 << 17), /* PMP attached */ |
| 160 | PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ | 166 | PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ |
| @@ -178,13 +184,14 @@ enum { | |||
| 178 | AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ | 184 | AHCI_HFLAG_MV_PATA = (1 << 4), /* PATA port */ |
| 179 | AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ | 185 | AHCI_HFLAG_NO_MSI = (1 << 5), /* no PCI MSI */ |
| 180 | AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ | 186 | AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ |
| 187 | AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */ | ||
| 181 | 188 | ||
| 182 | /* ap->flags bits */ | 189 | /* ap->flags bits */ |
| 183 | AHCI_FLAG_NO_HOTPLUG = (1 << 24), /* ignore PxSERR.DIAG.N */ | ||
| 184 | 190 | ||
| 185 | AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | | 191 | AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | |
| 186 | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | | 192 | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | |
| 187 | ATA_FLAG_ACPI_SATA | ATA_FLAG_AN, | 193 | ATA_FLAG_ACPI_SATA | ATA_FLAG_AN | |
| 194 | ATA_FLAG_IPM, | ||
| 188 | AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY, | 195 | AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY, |
| 189 | }; | 196 | }; |
| 190 | 197 | ||
| @@ -254,6 +261,11 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); | |||
| 254 | static int ahci_pci_device_resume(struct pci_dev *pdev); | 261 | static int ahci_pci_device_resume(struct pci_dev *pdev); |
| 255 | #endif | 262 | #endif |
| 256 | 263 | ||
| 264 | static struct class_device_attribute *ahci_shost_attrs[] = { | ||
| 265 | &class_device_attr_link_power_management_policy, | ||
| 266 | NULL | ||
| 267 | }; | ||
| 268 | |||
| 257 | static struct scsi_host_template ahci_sht = { | 269 | static struct scsi_host_template ahci_sht = { |
| 258 | .module = THIS_MODULE, | 270 | .module = THIS_MODULE, |
| 259 | .name = DRV_NAME, | 271 | .name = DRV_NAME, |
| @@ -271,6 +283,7 @@ static struct scsi_host_template ahci_sht = { | |||
| 271 | .slave_configure = ata_scsi_slave_config, | 283 | .slave_configure = ata_scsi_slave_config, |
| 272 | .slave_destroy = ata_scsi_slave_destroy, | 284 | .slave_destroy = ata_scsi_slave_destroy, |
| 273 | .bios_param = ata_std_bios_param, | 285 | .bios_param = ata_std_bios_param, |
| 286 | .shost_attrs = ahci_shost_attrs, | ||
| 274 | }; | 287 | }; |
| 275 | 288 | ||
| 276 | static const struct ata_port_operations ahci_ops = { | 289 | static const struct ata_port_operations ahci_ops = { |
| @@ -302,6 +315,8 @@ static const struct ata_port_operations ahci_ops = { | |||
| 302 | .port_suspend = ahci_port_suspend, | 315 | .port_suspend = ahci_port_suspend, |
| 303 | .port_resume = ahci_port_resume, | 316 | .port_resume = ahci_port_resume, |
| 304 | #endif | 317 | #endif |
| 318 | .enable_pm = ahci_enable_alpm, | ||
| 319 | .disable_pm = ahci_disable_alpm, | ||
| 305 | 320 | ||
| 306 | .port_start = ahci_port_start, | 321 | .port_start = ahci_port_start, |
| 307 | .port_stop = ahci_port_stop, | 322 | .port_stop = ahci_port_stop, |
| @@ -836,6 +851,130 @@ static void ahci_power_up(struct ata_port *ap) | |||
| 836 | writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); | 851 | writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); |
| 837 | } | 852 | } |
| 838 | 853 | ||
| 854 | static void ahci_disable_alpm(struct ata_port *ap) | ||
| 855 | { | ||
| 856 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
| 857 | void __iomem *port_mmio = ahci_port_base(ap); | ||
| 858 | u32 cmd; | ||
| 859 | struct ahci_port_priv *pp = ap->private_data; | ||
| 860 | |||
| 861 | /* IPM bits should be disabled by libata-core */ | ||
| 862 | /* get the existing command bits */ | ||
| 863 | cmd = readl(port_mmio + PORT_CMD); | ||
| 864 | |||
| 865 | /* disable ALPM and ASP */ | ||
| 866 | cmd &= ~PORT_CMD_ASP; | ||
| 867 | cmd &= ~PORT_CMD_ALPE; | ||
| 868 | |||
| 869 | /* force the interface back to active */ | ||
| 870 | cmd |= PORT_CMD_ICC_ACTIVE; | ||
| 871 | |||
| 872 | /* write out new cmd value */ | ||
| 873 | writel(cmd, port_mmio + PORT_CMD); | ||
| 874 | cmd = readl(port_mmio + PORT_CMD); | ||
| 875 | |||
| 876 | /* wait 10ms to be sure we've come out of any low power state */ | ||
| 877 | msleep(10); | ||
| 878 | |||
| 879 | /* clear out any PhyRdy stuff from interrupt status */ | ||
| 880 | writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT); | ||
| 881 | |||
| 882 | /* go ahead and clean out PhyRdy Change from Serror too */ | ||
| 883 | ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18))); | ||
| 884 | |||
| 885 | /* | ||
| 886 | * Clear flag to indicate that we should ignore all PhyRdy | ||
| 887 | * state changes | ||
| 888 | */ | ||
| 889 | hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG; | ||
| 890 | |||
| 891 | /* | ||
| 892 | * Enable interrupts on Phy Ready. | ||
| 893 | */ | ||
| 894 | pp->intr_mask |= PORT_IRQ_PHYRDY; | ||
| 895 | writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); | ||
| 896 | |||
| 897 | /* | ||
| 898 | * don't change the link pm policy - we can be called | ||
| 899 | * just to turn of link pm temporarily | ||
| 900 | */ | ||
| 901 | } | ||
| 902 | |||
| 903 | static int ahci_enable_alpm(struct ata_port *ap, | ||
| 904 | enum link_pm policy) | ||
| 905 | { | ||
| 906 | struct ahci_host_priv *hpriv = ap->host->private_data; | ||
| 907 | void __iomem *port_mmio = ahci_port_base(ap); | ||
| 908 | u32 cmd; | ||
| 909 | struct ahci_port_priv *pp = ap->private_data; | ||
| 910 | u32 asp; | ||
| 911 | |||
| 912 | /* Make sure the host is capable of link power management */ | ||
| 913 | if (!(hpriv->cap & HOST_CAP_ALPM)) | ||
| 914 | return -EINVAL; | ||
| 915 | |||
| 916 | switch (policy) { | ||
| 917 | case MAX_PERFORMANCE: | ||
| 918 | case NOT_AVAILABLE: | ||
| 919 | /* | ||
| 920 | * if we came here with NOT_AVAILABLE, | ||
| 921 | * it just means this is the first time we | ||
| 922 | * have tried to enable - default to max performance, | ||
| 923 | * and let the user go to lower power modes on request. | ||
| 924 | */ | ||
| 925 | ahci_disable_alpm(ap); | ||
| 926 | return 0; | ||
| 927 | case MIN_POWER: | ||
| 928 | /* configure HBA to enter SLUMBER */ | ||
| 929 | asp = PORT_CMD_ASP; | ||
| 930 | break; | ||
| 931 | case MEDIUM_POWER: | ||
| 932 | /* configure HBA to enter PARTIAL */ | ||
| 933 | asp = 0; | ||
| 934 | break; | ||
| 935 | default: | ||
| 936 | return -EINVAL; | ||
| 937 | } | ||
| 938 | |||
| 939 | /* | ||
| 940 | * Disable interrupts on Phy Ready. This keeps us from | ||
| 941 | * getting woken up due to spurious phy ready interrupts | ||
| 942 | * TBD - Hot plug should be done via polling now, is | ||
| 943 | * that even supported? | ||
| 944 | */ | ||
| 945 | pp->intr_mask &= ~PORT_IRQ_PHYRDY; | ||
| 946 | writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); | ||
| 947 | |||
| 948 | /* | ||
| 949 | * Set a flag to indicate that we should ignore all PhyRdy | ||
| 950 | * state changes since these can happen now whenever we | ||
| 951 | * change link state | ||
| 952 | */ | ||
| 953 | hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG; | ||
| 954 | |||
| 955 | /* get the existing command bits */ | ||
| 956 | cmd = readl(port_mmio + PORT_CMD); | ||
| 957 | |||
| 958 | /* | ||
| 959 | * Set ASP based on Policy | ||
| 960 | */ | ||
| 961 | cmd |= asp; | ||
| 962 | |||
| 963 | /* | ||
| 964 | * Setting this bit will instruct the HBA to aggressively | ||
| 965 | * enter a lower power link state when it's appropriate and | ||
| 966 | * based on the value set above for ASP | ||
| 967 | */ | ||
| 968 | cmd |= PORT_CMD_ALPE; | ||
| 969 | |||
| 970 | /* write out new cmd value */ | ||
| 971 | writel(cmd, port_mmio + PORT_CMD); | ||
| 972 | cmd = readl(port_mmio + PORT_CMD); | ||
| 973 | |||
| 974 | /* IPM bits should be set by libata-core */ | ||
| 975 | return 0; | ||
| 976 | } | ||
| 977 | |||
| 839 | #ifdef CONFIG_PM | 978 | #ifdef CONFIG_PM |
| 840 | static void ahci_power_down(struct ata_port *ap) | 979 | static void ahci_power_down(struct ata_port *ap) |
| 841 | { | 980 | { |
| @@ -1504,6 +1643,17 @@ static void ahci_port_intr(struct ata_port *ap) | |||
| 1504 | if (unlikely(resetting)) | 1643 | if (unlikely(resetting)) |
| 1505 | status &= ~PORT_IRQ_BAD_PMP; | 1644 | status &= ~PORT_IRQ_BAD_PMP; |
| 1506 | 1645 | ||
| 1646 | /* If we are getting PhyRdy, this is | ||
| 1647 | * just a power state change, we should | ||
| 1648 | * clear out this, plus the PhyRdy/Comm | ||
| 1649 | * Wake bits from Serror | ||
| 1650 | */ | ||
| 1651 | if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) && | ||
| 1652 | (status & PORT_IRQ_PHYRDY)) { | ||
| 1653 | status &= ~PORT_IRQ_PHYRDY; | ||
| 1654 | ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18))); | ||
| 1655 | } | ||
| 1656 | |||
| 1507 | if (unlikely(status & PORT_IRQ_ERROR)) { | 1657 | if (unlikely(status & PORT_IRQ_ERROR)) { |
| 1508 | ahci_error_intr(ap, status); | 1658 | ahci_error_intr(ap, status); |
| 1509 | return; | 1659 | return; |
| @@ -2151,6 +2301,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 2151 | ata_port_pbar_desc(ap, AHCI_PCI_BAR, | 2301 | ata_port_pbar_desc(ap, AHCI_PCI_BAR, |
| 2152 | 0x100 + ap->port_no * 0x80, "port"); | 2302 | 0x100 + ap->port_no * 0x80, "port"); |
| 2153 | 2303 | ||
| 2304 | /* set initial link pm policy */ | ||
| 2305 | ap->pm_policy = NOT_AVAILABLE; | ||
| 2306 | |||
| 2154 | /* standard SATA port setup */ | 2307 | /* standard SATA port setup */ |
| 2155 | if (hpriv->port_map & (1 << i)) | 2308 | if (hpriv->port_map & (1 << i)) |
| 2156 | ap->ioaddr.cmd_addr = port_mmio; | 2309 | ap->ioaddr.cmd_addr = port_mmio; |
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index e512903b8dbb..63035d71a61a 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 | ||
| @@ -6362,6 +6547,12 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg) | |||
| 6362 | { | 6547 | { |
| 6363 | int rc; | 6548 | int rc; |
| 6364 | 6549 | ||
| 6550 | /* | ||
| 6551 | * disable link pm on all ports before requesting | ||
| 6552 | * any pm activity | ||
| 6553 | */ | ||
| 6554 | ata_lpm_enable(host); | ||
| 6555 | |||
| 6365 | rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1); | 6556 | rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1); |
| 6366 | if (rc == 0) | 6557 | if (rc == 0) |
| 6367 | host->dev->power.power_state = mesg; | 6558 | host->dev->power.power_state = mesg; |
| @@ -6384,6 +6575,9 @@ void ata_host_resume(struct ata_host *host) | |||
| 6384 | ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET, | 6575 | ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET, |
| 6385 | ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0); | 6576 | ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0); |
| 6386 | host->dev->power.power_state = PMSG_ON; | 6577 | host->dev->power.power_state = PMSG_ON; |
| 6578 | |||
| 6579 | /* reenable link pm */ | ||
| 6580 | ata_lpm_disable(host); | ||
| 6387 | } | 6581 | } |
| 6388 | #endif | 6582 | #endif |
| 6389 | 6583 | ||
| @@ -6926,6 +7120,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) | |||
| 6926 | struct ata_port *ap = host->ports[i]; | 7120 | struct ata_port *ap = host->ports[i]; |
| 6927 | 7121 | ||
| 6928 | ata_scsi_scan_host(ap, 1); | 7122 | ata_scsi_scan_host(ap, 1); |
| 7123 | ata_lpm_schedule(ap, ap->pm_policy); | ||
| 6929 | } | 7124 | } |
| 6930 | 7125 | ||
| 6931 | return 0; | 7126 | return 0; |
| @@ -7322,7 +7517,6 @@ const struct ata_port_info ata_dummy_port_info = { | |||
| 7322 | * likely to change as new drivers are added and updated. | 7517 | * likely to change as new drivers are added and updated. |
| 7323 | * Do not depend on ABI/API stability. | 7518 | * Do not depend on ABI/API stability. |
| 7324 | */ | 7519 | */ |
| 7325 | |||
| 7326 | EXPORT_SYMBOL_GPL(sata_deb_timing_normal); | 7520 | EXPORT_SYMBOL_GPL(sata_deb_timing_normal); |
| 7327 | EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); | 7521 | EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); |
| 7328 | EXPORT_SYMBOL_GPL(sata_deb_timing_long); | 7522 | 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 | ||
