aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-01-20 12:10:11 -0500
committerJeff Garzik <jeff@garzik.org>2007-01-24 02:03:45 -0500
commit07c53dac4904206a50dd7c87adabbb1acff903fb (patch)
tree09fb7d1b53b4e6b5aabf05139ca8fff866e7e8d0 /drivers/ata
parentf740d1689d91415cfc749d17138a11ed03b7d38b (diff)
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: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/ahci.c37
1 files changed, 10 insertions, 27 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index bd241767caea..e3c7b312287a 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -586,35 +586,18 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap)
586{ 586{
587 u32 cmd, scontrol; 587 u32 cmd, scontrol;
588 588
589 cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK; 589 if (!(cap & HOST_CAP_SSS))
590 590 return;
591 if (cap & HOST_CAP_SSC) {
592 /* enable transitions to slumber mode */
593 scontrol = readl(port_mmio + PORT_SCR_CTL);
594 if ((scontrol & 0x0f00) > 0x100) {
595 scontrol &= ~0xf00;
596 writel(scontrol, port_mmio + PORT_SCR_CTL);
597 }
598
599 /* put device into slumber mode */
600 writel(cmd | PORT_CMD_ICC_SLUMBER, port_mmio + PORT_CMD);
601
602 /* wait for the transition to complete */
603 ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_ICC_SLUMBER,
604 PORT_CMD_ICC_SLUMBER, 1, 50);
605 }
606 591
607 /* put device into listen mode */ 592 /* put device into listen mode, first set PxSCTL.DET to 0 */
608 if (cap & HOST_CAP_SSS) { 593 scontrol = readl(port_mmio + PORT_SCR_CTL);
609 /* first set PxSCTL.DET to 0 */ 594 scontrol &= ~0xf;
610 scontrol = readl(port_mmio + PORT_SCR_CTL); 595 writel(scontrol, port_mmio + PORT_SCR_CTL);
611 scontrol &= ~0xf;
612 writel(scontrol, port_mmio + PORT_SCR_CTL);
613 596
614 /* then set PxCMD.SUD to 0 */ 597 /* then set PxCMD.SUD to 0 */
615 cmd &= ~PORT_CMD_SPIN_UP; 598 cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
616 writel(cmd, port_mmio + PORT_CMD); 599 cmd &= ~PORT_CMD_SPIN_UP;
617 } 600 writel(cmd, port_mmio + PORT_CMD);
618} 601}
619 602
620static void ahci_init_port(void __iomem *port_mmio, u32 cap, 603static void ahci_init_port(void __iomem *port_mmio, u32 cap,