Commit d2e75dff authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

ahci: separate out ahci_kick_engine()

Separate out stop_engine - CLO - start_engine sequence from
ahci_softreset() and ahci_clo() into ahci_reset_engine() and use it in
ahci_softreset() and ahci_post_internal_cmd().  The function will also
be used to prepare for and clean up after PMP register access
commands.
Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 2cbb79eb
...@@ -948,25 +948,49 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag, ...@@ -948,25 +948,49 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16); pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
} }
static int ahci_clo(struct ata_port *ap) static int ahci_kick_engine(struct ata_port *ap, int force_restart)
{ {
void __iomem *port_mmio = ap->ioaddr.cmd_addr; void __iomem *port_mmio = ap->ioaddr.cmd_addr;
struct ahci_host_priv *hpriv = ap->host->private_data; struct ahci_host_priv *hpriv = ap->host->private_data;
u32 tmp; u32 tmp;
int busy, rc;
if (!(hpriv->cap & HOST_CAP_CLO)) /* do we need to kick the port? */
return -EOPNOTSUPP; busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
if (!busy && !force_restart)
return 0;
/* stop engine */
rc = ahci_stop_engine(ap);
if (rc)
goto out_restart;
/* need to do CLO? */
if (!busy) {
rc = 0;
goto out_restart;
}
if (!(hpriv->cap & HOST_CAP_CLO)) {
rc = -EOPNOTSUPP;
goto out_restart;
}
/* perform CLO */
tmp = readl(port_mmio + PORT_CMD); tmp = readl(port_mmio + PORT_CMD);
tmp |= PORT_CMD_CLO; tmp |= PORT_CMD_CLO;
writel(tmp, port_mmio + PORT_CMD); writel(tmp, port_mmio + PORT_CMD);
rc = 0;
tmp = ata_wait_register(port_mmio + PORT_CMD, tmp = ata_wait_register(port_mmio + PORT_CMD,
PORT_CMD_CLO, PORT_CMD_CLO, 1, 500); PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
if (tmp & PORT_CMD_CLO) if (tmp & PORT_CMD_CLO)
return -EIO; rc = -EIO;
return 0; /* restart engine */
out_restart:
ahci_start_engine(ap);
return rc;
} }
static int ahci_softreset(struct ata_port *ap, unsigned int *class, static int ahci_softreset(struct ata_port *ap, unsigned int *class,
...@@ -991,27 +1015,10 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, ...@@ -991,27 +1015,10 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
} }
/* prepare for SRST (AHCI-1.1 10.4.1) */ /* prepare for SRST (AHCI-1.1 10.4.1) */
rc = ahci_stop_engine(ap); rc = ahci_kick_engine(ap, 1);
if (rc) { if (rc)
reason = "failed to stop engine"; ata_port_printk(ap, KERN_WARNING,
goto fail_restart; "failed to reset engine (errno=%d)", rc);
}
/* check BUSY/DRQ, perform Command List Override if necessary */
if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
rc = ahci_clo(ap);
if (rc == -EOPNOTSUPP) {
reason = "port busy but CLO unavailable";
goto fail_restart;
} else if (rc) {
reason = "port busy but CLO failed";
goto fail_restart;
}
}
/* restart engine */
ahci_start_engine(ap);
ata_tf_init(ap->device, &tf); ata_tf_init(ap->device, &tf);
fis = pp->cmd_tbl; fis = pp->cmd_tbl;
...@@ -1070,8 +1077,6 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class, ...@@ -1070,8 +1077,6 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
DPRINTK("EXIT, class=%u\n", *class); DPRINTK("EXIT, class=%u\n", *class);
return 0; return 0;
fail_restart:
ahci_start_engine(ap);
fail: fail:
ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
return rc; return rc;
...@@ -1516,11 +1521,9 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) ...@@ -1516,11 +1521,9 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{ {
struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap;
if (qc->flags & ATA_QCFLAG_FAILED) {
/* make DMA engine forget about the failed command */ /* make DMA engine forget about the failed command */
ahci_stop_engine(ap); if (qc->flags & ATA_QCFLAG_FAILED)
ahci_start_engine(ap); ahci_kick_engine(ap, 1);
}
} }
static int ahci_port_resume(struct ata_port *ap) static int ahci_port_resume(struct ata_port *ap)
......
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