OSDN Git Service

Merge branch 'for-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
[uclinux-h8/linux.git] / drivers / ata / libahci.c
index 09620c2..b5f57c6 100644 (file)
@@ -801,6 +801,8 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
                        cmd |= PORT_CMD_ALPE;
                        if (policy == ATA_LPM_MIN_POWER)
                                cmd |= PORT_CMD_ASP;
+                       else if (policy == ATA_LPM_MIN_POWER_WITH_PARTIAL)
+                               cmd &= ~PORT_CMD_ASP;
 
                        /* write out new cmd value */
                        writel(cmd, port_mmio + PORT_CMD);
@@ -811,7 +813,8 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
        if ((hpriv->cap2 & HOST_CAP2_SDS) &&
            (hpriv->cap2 & HOST_CAP2_SADM) &&
            (link->device->flags & ATA_DFLAG_DEVSLP)) {
-               if (policy == ATA_LPM_MIN_POWER)
+               if (policy == ATA_LPM_MIN_POWER ||
+                   policy == ATA_LPM_MIN_POWER_WITH_PARTIAL)
                        ahci_set_aggressive_devslp(ap, true);
                else
                        ahci_set_aggressive_devslp(ap, false);
@@ -2107,7 +2110,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
        struct ahci_host_priv *hpriv = ap->host->private_data;
        void __iomem *port_mmio = ahci_port_base(ap);
        struct ata_device *dev = ap->link.device;
-       u32 devslp, dm, dito, mdat, deto;
+       u32 devslp, dm, dito, mdat, deto, dito_conf;
        int rc;
        unsigned int err_mask;
 
@@ -2131,8 +2134,15 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
                return;
        }
 
-       /* device sleep was already enabled */
-       if (devslp & PORT_DEVSLP_ADSE)
+       dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET;
+       dito = devslp_idle_timeout / (dm + 1);
+       if (dito > 0x3ff)
+               dito = 0x3ff;
+
+       dito_conf = (devslp >> PORT_DEVSLP_DITO_OFFSET) & 0x3FF;
+
+       /* device sleep was already enabled and same dito */
+       if ((devslp & PORT_DEVSLP_ADSE) && (dito_conf == dito))
                return;
 
        /* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */
@@ -2140,11 +2150,6 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
        if (rc)
                return;
 
-       dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET;
-       dito = devslp_idle_timeout / (dm + 1);
-       if (dito > 0x3ff)
-               dito = 0x3ff;
-
        /* Use the nominal value 10 ms if the read MDAT is zero,
         * the nominal value of DETO is 20 ms.
         */
@@ -2162,6 +2167,8 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
                deto = 20;
        }
 
+       /* Make dito, mdat, deto bits to 0s */
+       devslp &= ~GENMASK_ULL(24, 2);
        devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) |
                   (mdat << PORT_DEVSLP_MDAT_OFFSET) |
                   (deto << PORT_DEVSLP_DETO_OFFSET) |
@@ -2439,6 +2446,8 @@ static void ahci_port_stop(struct ata_port *ap)
         * re-enabling INTx.
         */
        writel(1 << ap->port_no, host_mmio + HOST_IRQ_STAT);
+
+       ahci_rpm_put_port(ap);
 }
 
 void ahci_print_info(struct ata_host *host, const char *scc_s)