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

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
Loading
Loading
Loading
Loading
+36 −33
Original line number Diff line number Diff line
@@ -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);
}

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;
	struct ahci_host_priv *hpriv = ap->host->private_data;
	u32 tmp;
	int busy, rc;

	if (!(hpriv->cap & HOST_CAP_CLO))
		return -EOPNOTSUPP;
	/* do we need to kick the port? */
	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 |= PORT_CMD_CLO;
	writel(tmp, port_mmio + PORT_CMD);

	rc = 0;
	tmp = ata_wait_register(port_mmio + PORT_CMD,
				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
	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,
@@ -991,27 +1015,10 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
	}

	/* prepare for SRST (AHCI-1.1 10.4.1) */
	rc = ahci_stop_engine(ap);
	if (rc) {
		reason = "failed to stop engine";
		goto fail_restart;
	}

	/* 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);
	rc = ahci_kick_engine(ap, 1);
	if (rc)
		ata_port_printk(ap, KERN_WARNING,
				"failed to reset engine (errno=%d)", rc);

	ata_tf_init(ap->device, &tf);
	fis = pp->cmd_tbl;
@@ -1070,8 +1077,6 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
	DPRINTK("EXIT, class=%u\n", *class);
	return 0;

 fail_restart:
	ahci_start_engine(ap);
 fail:
	ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
	return rc;
@@ -1516,11 +1521,9 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{
	struct ata_port *ap = qc->ap;

	if (qc->flags & ATA_QCFLAG_FAILED) {
	/* make DMA engine forget about the failed command */
		ahci_stop_engine(ap);
		ahci_start_engine(ap);
	}
	if (qc->flags & ATA_QCFLAG_FAILED)
		ahci_kick_engine(ap, 1);
}

static int ahci_port_resume(struct ata_port *ap)