Commit c98fc827 authored by Jeff Garzik's avatar Jeff Garzik

[libata] catch, and ack, spurious DMA interrupts

Hardware issue on Intel ICH5 requires an additional ack sequence
over and above the normal IDE DMA interrupt ack requirements.  Issue
described in post to freebsd list:
http://www.mail-archive.com/freebsd-stable@freebsd.org/msg58421.html

Since the bug workaround only requires a single additional PIO or
MMIO read in the interrupt handler, it is applied to all chipsets
using the standard libata interrupt handler.

Credit for research the issue, creating the patch, and testing the
patch all go to Jon Burgess.
parent d0d0b2da
......@@ -2385,6 +2385,41 @@ static inline unsigned int ata_host_intr (struct ata_port *ap,
return handled;
}
/**
* ata_chk_spurious_int - Check for spurious interrupts
* @ap: port to which command is being issued
*
* Examines the DMA status registers and clears
* unexpected interrupts. Created to work around
* hardware bug on Intel ICH5, but is applied to all
* chipsets using the standard irq handler, just for safety.
* If the bug is not present, this is simply a single
* PIO or MMIO read addition to the irq handler.
*
* LOCKING:
*/
static inline void ata_chk_spurious_int(struct ata_port *ap) {
int host_stat;
if (ap->flags & ATA_FLAG_MMIO) {
void *mmio = (void *) ap->ioaddr.bmdma_addr;
host_stat = readb(mmio + ATA_DMA_STATUS);
} else
host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
if ((host_stat & (ATA_DMA_INTR | ATA_DMA_ERR | ATA_DMA_ACTIVE)) == ATA_DMA_INTR) {
if (ap->flags & ATA_FLAG_MMIO) {
void *mmio = (void *) ap->ioaddr.bmdma_addr;
writeb(host_stat & ~ATA_DMA_ERR, mmio + ATA_DMA_STATUS);
} else
outb(host_stat & ~ATA_DMA_ERR, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
DPRINTK("ata%u: Caught spurious interrupt, status 0x%X\n", ap->id, host_stat);
udelay(1);
}
}
/**
* ata_interrupt -
* @irq:
......@@ -2417,6 +2452,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0))
handled += ata_host_intr(ap, qc);
ata_chk_spurious_int(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