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

Commit c02c873c authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev:
  libata-sff: fix spurious IRQ handling
  pata_via: Add VIA VX900 support
parents 541e40ee 332ac7ff
Loading
Loading
Loading
Loading
+36 −7
Original line number Diff line number Diff line
@@ -1667,6 +1667,7 @@ unsigned int ata_sff_host_intr(struct ata_port *ap,
{
	struct ata_eh_info *ehi = &ap->link.eh_info;
	u8 status, host_stat = 0;
	bool bmdma_stopped = false;

	VPRINTK("ata%u: protocol %d task_state %d\n",
		ap->print_id, qc->tf.protocol, ap->hsm_task_state);
@@ -1699,6 +1700,7 @@ unsigned int ata_sff_host_intr(struct ata_port *ap,

			/* before we do anything else, clear DMA-Start bit */
			ap->ops->bmdma_stop(qc);
			bmdma_stopped = true;

			if (unlikely(host_stat & ATA_DMA_ERR)) {
				/* error when transfering data to/from memory */
@@ -1716,8 +1718,14 @@ unsigned int ata_sff_host_intr(struct ata_port *ap,

	/* check main status, clearing INTRQ if needed */
	status = ata_sff_irq_status(ap);
	if (status & ATA_BUSY)
	if (status & ATA_BUSY) {
		if (bmdma_stopped) {
			/* BMDMA engine is already stopped, we're screwed */
			qc->err_mask |= AC_ERR_HSM;
			ap->hsm_task_state = HSM_ST_ERR;
		} else
			goto idle_irq;
	}

	/* ack bmdma irq events */
	ap->ops->sff_irq_clear(ap);
@@ -1762,13 +1770,16 @@ EXPORT_SYMBOL_GPL(ata_sff_host_intr);
irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
{
	struct ata_host *host = dev_instance;
	bool retried = false;
	unsigned int i;
	unsigned int handled = 0, polling = 0;
	unsigned int handled, idle, polling;
	unsigned long flags;

	/* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
	spin_lock_irqsave(&host->lock, flags);

retry:
	handled = idle = polling = 0;
	for (i = 0; i < host->n_ports; i++) {
		struct ata_port *ap = host->ports[i];
		struct ata_queued_cmd *qc;
@@ -1782,7 +1793,8 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
				handled |= ata_sff_host_intr(ap, qc);
			else
				polling |= 1 << i;
		}
		} else
			idle |= 1 << i;
	}

	/*
@@ -1790,7 +1802,9 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
	 * asserting IRQ line, nobody cared will ensue.  Check IRQ
	 * pending status if available and clear spurious IRQ.
	 */
	if (!handled) {
	if (!handled && !retried) {
		bool retry = false;

		for (i = 0; i < host->n_ports; i++) {
			struct ata_port *ap = host->ports[i];

@@ -1805,8 +1819,23 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
				ata_port_printk(ap, KERN_INFO,
						"clearing spurious IRQ\n");

			if (idle & (1 << i)) {
				ap->ops->sff_check_status(ap);
				ap->ops->sff_irq_clear(ap);
			} else {
				/* clear INTRQ and check if BUSY cleared */
				if (!(ap->ops->sff_check_status(ap) & ATA_BUSY))
					retry |= true;
				/*
				 * With command in flight, we can't do
				 * sff_irq_clear() w/o racing with completion.
				 */
			}
		}

		if (retry) {
			retried = true;
			goto retry;
		}
	}

+1 −0
Original line number Diff line number Diff line
@@ -677,6 +677,7 @@ static const struct pci_device_id via[] = {
	{ PCI_VDEVICE(VIA, 0x3164), },
	{ PCI_VDEVICE(VIA, 0x5324), },
	{ PCI_VDEVICE(VIA, 0xC409), VIA_IDFLAG_SINGLE },
	{ PCI_VDEVICE(VIA, 0x9001), VIA_IDFLAG_SINGLE },

	{ },
};