aboutsummaryrefslogtreecommitdiff
path: root/drivers/ata
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-11-20 15:42:36 +0900
committerTejun Heo <htejun@gmail.com>2006-12-03 17:56:29 +0900
commit8e16f941226f15622fbbc416a1f3d8705001a191 (patch)
tree97bf87ebff9e3e69caa0a0ebdd9ee9291c5dfac5 /drivers/ata
parent70e6ad0c6d1e6cb9ee3c036a85ca2561eb1fd766 (diff)
[PATCH] ahci: do not powerdown during initialization
ahci_init_controller() calls ahci_deinit_port() to make sure the controller is stopped before initializing the controller. In turn, ahci_deinit_port() invokes ahci_power_down() to power down the port. If the controller supports slumber mode, the link is put into it. Unfortunately, some devices don't implement link powersaving mode properly and show erratic behavior after link is put into slumber mode. For example, HL-DT-ST DVD-RAM GSA-H30N completely locks up on slumber transition and can only be recovered with the *REAL* hard reset - power removal and reapply. Note that this makes the first probing reset different from all others. If the above dvd-ram is hotplugged after ahci is initialized, no problem occurs because ahci is already fully initialized with phy powered up. So, this might also be the reason for other weird AHCI initial probing abnormalities. This patch moves power up/down out of port init/deinit and call them only when needed. Power down is now called only when suspending. As system suspend usually involves powering down 12v for storage devices, this shouldn't cause problem even if the attached device doesn't support slumber mode. However, in partial power management and suspend failure cases, devices might lock up after suspend attempt. I thought about removing transition to slumber mode altogether but ahci spec mandates it before HBA D3 state transition. Blacklisting such devices might be the solution. Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/ahci.c14
1 files changed, 7 insertions, 7 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index af3565d1fef..f36da488a2c 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -612,9 +612,6 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap)
static void ahci_init_port(void __iomem *port_mmio, u32 cap,
dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
{
- /* power up */
- ahci_power_up(port_mmio, cap);
-
/* enable FIS reception */
ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
@@ -640,9 +637,6 @@ static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
return rc;
}
- /* put device into slumber mode */
- ahci_power_down(port_mmio, cap);
-
return 0;
}
@@ -1321,7 +1315,9 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
int rc;
rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
- if (rc) {
+ if (rc == 0)
+ ahci_power_down(port_mmio, hpriv->cap);
+ else {
ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
ahci_init_port(port_mmio, hpriv->cap,
pp->cmd_slot_dma, pp->rx_fis_dma);
@@ -1337,6 +1333,7 @@ static int ahci_port_resume(struct ata_port *ap)
void __iomem *mmio = ap->host->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ ahci_power_up(port_mmio, hpriv->cap);
ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
return 0;
@@ -1443,6 +1440,9 @@ static int ahci_port_start(struct ata_port *ap)
ap->private_data = pp;
+ /* power up port */
+ ahci_power_up(port_mmio, hpriv->cap);
+
/* initialize port */
ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);