Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

sata_inic162x: use IDMA for ATAPI commands



Use IDMA for ATAPI commands.  Write and some misc commands time out
when executed using ATAPI_PROT_DMA but ATAPI_PROT_PIO works fine.  As
PIO is driven by DMA too, it doesn't make any noticeable difference
for native SATA devices.  inic_check_atapi_dma() is implemented to
force PIO for those ATAPI commands.

After this change, sata_inic162x issues all commands using IDMA.

Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent 049e8e04
Loading
Loading
Loading
Loading
+47 −34
Original line number Diff line number Diff line
@@ -192,7 +192,8 @@ struct inic_prd {

struct inic_pkt {
	struct inic_cpb	cpb;
	struct inic_prd	prd[LIBATA_MAX_PRD];
	struct inic_prd	prd[LIBATA_MAX_PRD + 1];	/* + 1 for cdb */
	u8		cdb[ATAPI_CDB_LEN];
} __packed;

struct inic_host_priv {
@@ -361,7 +362,6 @@ static void inic_host_intr(struct ata_port *ap)
		goto spurious;
	}

	if (!ata_is_atapi(qc->tf.protocol)) {
	if (likely(idma_stat & IDMA_STAT_DONE)) {
		inic_stop_idma(ap);

@@ -375,10 +375,6 @@ static void inic_host_intr(struct ata_port *ap)
		ata_qc_complete(qc);
		return;
	}
	} else {
		if (likely(ata_sff_host_intr(ap, qc)))
			return;
	}

 spurious:
	ap->ops->sff_check_status(ap); /* clear ATA interrupt */
@@ -421,6 +417,19 @@ static irqreturn_t inic_interrupt(int irq, void *dev_instance)
	return IRQ_RETVAL(handled);
}

static int inic_check_atapi_dma(struct ata_queued_cmd *qc)
{
	/* For some reason ATAPI_PROT_DMA doesn't work for some
	 * commands including writes and other misc ops.  Use PIO
	 * protocol instead, which BTW is driven by the DMA engine
	 * anyway, so it shouldn't make much difference for native
	 * SATA devices.
	 */
	if (atapi_cmd_type(qc->cdb[0]) == READ)
		return 0;
	return 1;
}

static void inic_fill_sg(struct inic_prd *prd, struct ata_queued_cmd *qc)
{
	struct scatterlist *sg;
@@ -452,20 +461,21 @@ static void inic_qc_prep(struct ata_queued_cmd *qc)
	struct inic_prd *prd = pkt->prd;
	bool is_atapi = ata_is_atapi(qc->tf.protocol);
	bool is_data = ata_is_data(qc->tf.protocol);
	unsigned int cdb_len = 0;

	VPRINTK("ENTER\n");

	if (is_atapi)
		return;
		cdb_len = qc->dev->cdb_len;

	/* prepare packet, based on initio driver */
	memset(pkt, 0, sizeof(struct inic_pkt));

	cpb->ctl_flags = CPB_CTL_VALID | CPB_CTL_IEN;
	if (is_data)
	if (is_atapi || is_data)
		cpb->ctl_flags |= CPB_CTL_DATA;

	cpb->len = cpu_to_le32(qc->nbytes);
	cpb->len = cpu_to_le32(qc->nbytes + cdb_len);
	cpb->prd = cpu_to_le32(pp->pkt_dma + offsetof(struct inic_pkt, prd));

	cpb->device = qc->tf.device;
@@ -486,6 +496,18 @@ static void inic_qc_prep(struct ata_queued_cmd *qc)
	cpb->command = qc->tf.command;
	/* don't load ctl - dunno why.  it's like that in the initio driver */

	/* setup PRD for CDB */
	if (is_atapi) {
		memcpy(pkt->cdb, qc->cdb, ATAPI_CDB_LEN);
		prd->mad = cpu_to_le32(pp->pkt_dma +
				       offsetof(struct inic_pkt, cdb));
		prd->len = cpu_to_le16(cdb_len);
		prd->flags = PRD_CDB | PRD_WRITE;
		if (!is_data)
			prd->flags |= PRD_END;
		prd++;
	}

	/* setup sg table */
	if (is_data)
		inic_fill_sg(prd, qc);
@@ -498,7 +520,6 @@ static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
	struct ata_port *ap = qc->ap;
	void __iomem *port_base = inic_port_base(ap);

	if (!ata_is_atapi(qc->tf.protocol)) {
	/* fire up the ADMA engine */
	writew(HCTL_FTHD0, port_base + HOST_CTL);
	writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
@@ -507,9 +528,6 @@ static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
	return 0;
}

	return ata_sff_qc_issue(qc);
}

static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
{
	void __iomem *port_base = inic_port_base(ap);
@@ -698,6 +716,7 @@ static int inic_port_start(struct ata_port *ap)
static struct ata_port_operations inic_port_ops = {
	.inherits		= &ata_sff_port_ops,

	.check_atapi_dma	= inic_check_atapi_dma,
	.qc_prep		= inic_qc_prep,
	.qc_issue		= inic_qc_issue,
	.qc_fill_rtf		= inic_qc_fill_rtf,
@@ -717,12 +736,6 @@ static struct ata_port_operations inic_port_ops = {
};

static struct ata_port_info inic_port_info = {
	/* For some reason, ATAPI_PROT_PIO is broken on this
	 * controller, and no, PIO_POLLING does't fix it.  It somehow
	 * manages to report the wrong ireason and ignoring ireason
	 * results in machine lock up.  Tell libata to always prefer
	 * DMA.
	 */
	.flags			= ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
	.pio_mask		= 0x1f,	/* pio0-4 */
	.mwdma_mask		= 0x07, /* mwdma0-2 */