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

Commit 904c7bad authored by Mark Lord's avatar Mark Lord Committed by Jeff Garzik
Browse files

libata sata_qstor workaround for spurious interrupts



sata_qstor workaround for spurious interrupts.

The qstor hardware generates spurious interrupts from time to time when
switching in and out of packet mode.  These eventually result in the
IRQ being disabled, which kills other devices sharing this IRQ with us.

This workaround isn't perfect, but it's about the best we can do for
this hardware.  Spurious interrupts will still happen, but won't be
logged as such, and therefore won't cause the IRQ to be inadvertently
disabled.

Signed-off-by: default avatarMark Lord <mlord@pobox.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 12ee7d3c
Loading
Loading
Loading
Loading
+21 −17
Original line number Original line Diff line number Diff line
@@ -425,24 +425,27 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host)
		if (ap &&
		if (ap &&
		    !(ap->flags & ATA_FLAG_DISABLED)) {
		    !(ap->flags & ATA_FLAG_DISABLED)) {
			struct ata_queued_cmd *qc;
			struct ata_queued_cmd *qc;
			struct qs_port_priv *pp = ap->private_data;
			struct qs_port_priv *pp;
			if (!pp || pp->state != qs_state_mmio)
				continue;
			qc = ata_qc_from_tag(ap, ap->link.active_tag);
			qc = ata_qc_from_tag(ap, ap->link.active_tag);
			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
			if (!qc || !(qc->flags & ATA_QCFLAG_ACTIVE)) {

				/*
				/* check main status, clearing INTRQ */
				 * The qstor hardware generates spurious
				u8 status = ata_check_status(ap);
				 * interrupts from time to time when switching
				if ((status & ATA_BUSY))
				 * in and out of packet mode.
					continue;
				 * There's no obvious way to know if we're
				DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
				 * here now due to that, so just ack the irq
					ap->print_id, qc->tf.protocol, status);
				 * and pretend we knew it was ours.. (ugh).

				 * This does not affect packet mode.
				/* complete taskfile transaction */
				 */
				qc->err_mask |= ac_err_mask(status);
				ata_check_status(ap);
				ata_qc_complete(qc);
				handled = 1;
				handled = 1;
				continue;
			}
			}
			pp = ap->private_data;
			if (!pp || pp->state != qs_state_mmio)
				continue;
			if (!(qc->tf.flags & ATA_TFLAG_POLLING))
				handled |= ata_host_intr(ap, qc);
		}
		}
	}
	}
	return handled;
	return handled;
@@ -452,12 +455,13 @@ static irqreturn_t qs_intr(int irq, void *dev_instance)
{
{
	struct ata_host *host = dev_instance;
	struct ata_host *host = dev_instance;
	unsigned int handled = 0;
	unsigned int handled = 0;
	unsigned long flags;


	VPRINTK("ENTER\n");
	VPRINTK("ENTER\n");


	spin_lock(&host->lock);
	spin_lock_irqsave(&host->lock, flags);
	handled  = qs_intr_pkt(host) | qs_intr_mmio(host);
	handled  = qs_intr_pkt(host) | qs_intr_mmio(host);
	spin_unlock(&host->lock);
	spin_unlock_irqrestore(&host->lock, flags);


	VPRINTK("EXIT\n");
	VPRINTK("EXIT\n");