aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/libahci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/libahci.c')
-rw-r--r--drivers/ata/libahci.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index d61740e78d6d..402967902cbe 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -496,8 +496,8 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
496 } 496 }
497 } 497 }
498 498
499 /* fabricate port_map from cap.nr_ports */ 499 /* fabricate port_map from cap.nr_ports for < AHCI 1.3 */
500 if (!port_map) { 500 if (!port_map && vers < 0x10300) {
501 port_map = (1 << ahci_nr_ports(cap)) - 1; 501 port_map = (1 << ahci_nr_ports(cap)) - 1;
502 dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map); 502 dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map);
503 503
@@ -593,8 +593,22 @@ EXPORT_SYMBOL_GPL(ahci_start_engine);
593int ahci_stop_engine(struct ata_port *ap) 593int ahci_stop_engine(struct ata_port *ap)
594{ 594{
595 void __iomem *port_mmio = ahci_port_base(ap); 595 void __iomem *port_mmio = ahci_port_base(ap);
596 struct ahci_host_priv *hpriv = ap->host->private_data;
596 u32 tmp; 597 u32 tmp;
597 598
599 /*
600 * On some controllers, stopping a port's DMA engine while the port
601 * is in ALPM state (partial or slumber) results in failures on
602 * subsequent DMA engine starts. For those controllers, put the
603 * port back in active state before stopping its DMA engine.
604 */
605 if ((hpriv->flags & AHCI_HFLAG_WAKE_BEFORE_STOP) &&
606 (ap->link.lpm_policy > ATA_LPM_MAX_POWER) &&
607 ahci_set_lpm(&ap->link, ATA_LPM_MAX_POWER, ATA_LPM_WAKE_ONLY)) {
608 dev_err(ap->host->dev, "Failed to wake up port before engine stop\n");
609 return -EIO;
610 }
611
598 tmp = readl(port_mmio + PORT_CMD); 612 tmp = readl(port_mmio + PORT_CMD);
599 613
600 /* check if the HBA is idle */ 614 /* check if the HBA is idle */
@@ -689,6 +703,9 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
689 void __iomem *port_mmio = ahci_port_base(ap); 703 void __iomem *port_mmio = ahci_port_base(ap);
690 704
691 if (policy != ATA_LPM_MAX_POWER) { 705 if (policy != ATA_LPM_MAX_POWER) {
706 /* wakeup flag only applies to the max power policy */
707 hints &= ~ATA_LPM_WAKE_ONLY;
708
692 /* 709 /*
693 * Disable interrupts on Phy Ready. This keeps us from 710 * Disable interrupts on Phy Ready. This keeps us from
694 * getting woken up due to spurious phy ready 711 * getting woken up due to spurious phy ready
@@ -704,7 +721,8 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
704 u32 cmd = readl(port_mmio + PORT_CMD); 721 u32 cmd = readl(port_mmio + PORT_CMD);
705 722
706 if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) { 723 if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) {
707 cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE); 724 if (!(hints & ATA_LPM_WAKE_ONLY))
725 cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
708 cmd |= PORT_CMD_ICC_ACTIVE; 726 cmd |= PORT_CMD_ICC_ACTIVE;
709 727
710 writel(cmd, port_mmio + PORT_CMD); 728 writel(cmd, port_mmio + PORT_CMD);
@@ -712,6 +730,9 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
712 730
713 /* wait 10ms to be sure we've come out of LPM state */ 731 /* wait 10ms to be sure we've come out of LPM state */
714 ata_msleep(ap, 10); 732 ata_msleep(ap, 10);
733
734 if (hints & ATA_LPM_WAKE_ONLY)
735 return 0;
715 } else { 736 } else {
716 cmd |= PORT_CMD_ALPE; 737 cmd |= PORT_CMD_ALPE;
717 if (policy == ATA_LPM_MIN_POWER) 738 if (policy == ATA_LPM_MIN_POWER)