Commit 07c53dac authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

ahci: don't enter slumber on power down

Some ATA/ATAPI devices act weirdly after the link is put into slumber
mode.  Some hang completely requiring physical power removal while
others fail to wake up till the link is hardreset a couple of times.

The addition of slumber on power down was never driven by real need.
It just followed what ahci spec said literally.  The spec itself seems
faulty in that it doesn't consider devices (not controllers) which
don't support link powersaving mode.

Theory never matches reality when it comes to dark allys of cheap
ATA/ATAPI world.  It's just unrealistic to expect vendors to test
rarely used link powersaving feature rigorously.  This patch makes
ahci more friendly to the coldness of reality.

This shouldn't have any negative effect - when suspend operation
succeeds, we power off the whole machine; otherwise, we wake up
everything.  I can't see any reason to be so elaborate with powering
down the link in the first place.
Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent f740d168
...@@ -586,35 +586,18 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap) ...@@ -586,35 +586,18 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap)
{ {
u32 cmd, scontrol; u32 cmd, scontrol;
cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; if (!(cap & HOST_CAP_SSS))
return;
if (cap & HOST_CAP_SSC) {
/* enable transitions to slumber mode */
scontrol = readl(port_mmio + PORT_SCR_CTL);
if ((scontrol & 0x0f00) > 0x100) {
scontrol &= ~0xf00;
writel(scontrol, port_mmio + PORT_SCR_CTL);
}
/* put device into slumber mode */
writel(cmd | PORT_CMD_ICC_SLUMBER, port_mmio + PORT_CMD);
/* wait for the transition to complete */
ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_ICC_SLUMBER,
PORT_CMD_ICC_SLUMBER, 1, 50);
}
/* put device into listen mode */ /* put device into listen mode, first set PxSCTL.DET to 0 */
if (cap & HOST_CAP_SSS) { scontrol = readl(port_mmio + PORT_SCR_CTL);
/* first set PxSCTL.DET to 0 */ scontrol &= ~0xf;
scontrol = readl(port_mmio + PORT_SCR_CTL); writel(scontrol, port_mmio + PORT_SCR_CTL);
scontrol &= ~0xf;
writel(scontrol, port_mmio + PORT_SCR_CTL);
/* then set PxCMD.SUD to 0 */ /* then set PxCMD.SUD to 0 */
cmd &= ~PORT_CMD_SPIN_UP; cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
writel(cmd, port_mmio + PORT_CMD); cmd &= ~PORT_CMD_SPIN_UP;
} writel(cmd, port_mmio + PORT_CMD);
} }
static void ahci_init_port(void __iomem *port_mmio, u32 cap, static void ahci_init_port(void __iomem *port_mmio, u32 cap,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment