From: James Paradis <jparadis@redhat.com> Date: Fri, 6 Mar 2009 15:37:24 -0500 Subject: [ide] fix interrupt flood at startup w/ESB2 Message-id: 753202734.68691236371844598.JavaMail.root@zmail01.collab.prod.int.phx2.redhat.com O-Subject: Re: [RHEL5.4 PATCH] Fix interrupt flood at startup w/ESB2 IDE Bugzilla: 438979 RH-Acked-by: David Milburn <dmilburn@redhat.com> https://bugzilla.redhat.com/show_bug.cgi?id=438979 This patch was devised by Stratus to fix an interrupt flood we would get when using the IDE function of the ESB2. Most of the libata code does the right thing with clearing the interrupt bit when it's expected (e.g. after handling a DMA), but we ran into a case where the bit is unexpectedly set. It turns out that this controller has the quirk that the initial probe commands will also set the interrupt bit, even though we set the ATA_TFLAG_POLLING bit. With the POLLING bit clear, the interrupt handler falls through without hitting a code path that clears the bit. As a result we keep getting bombarded with interrupts. This patch clears the interrupt bit if we haven't handled the interrupt any other way, and it fixes the problem. I could use some help here, though: I'm not a libata expert, and there were some comments by Alan Cox in the bugzilla that I didn't quite understand... could somebody who knows libata help explain them to me? He seems to imply that maybe we want to fix this a different way... dmilburn and I have been going back and forth on this in bugzilla. Try this new patch; it treats this issue as a quirk and only clears the irq on specified hardware model(s): diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 71f55d1..ff18ba4 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -1547,6 +1547,12 @@ static int __devinit piix_init_one(struct pci_dev *pdev, } pci_set_master(pdev); + + /* ESB2 may generate DMA interrupts in PIO state */ + if (pdev->vendor == PCI_VENDOR_ID_INTEL && + pdev->device == PCI_DEVICE_ID_INTEL_ESB2_18) + host->flags |= ATA_HOST_ATAPI_SPURIOUS_INT; + return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht); } diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index afb816a..5fe674f 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1651,6 +1651,8 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance, struct pt_regs *pt_re if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) && (qc->flags & ATA_QCFLAG_ACTIVE)) handled |= ata_sff_host_intr(ap, qc); + else if(unlikely(host->flags & ATA_HOST_ATAPI_SPURIOUS_INT)) + ap->ops->sff_irq_clear(ap); } } diff --git a/include/linux/libata.h b/include/linux/libata.h index 53bcd7d..2b4509b 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -237,6 +237,7 @@ enum { /* host set flags */ ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */ ATA_HOST_STARTED = (1 << 1), /* Host started */ + ATA_HOST_ATAPI_SPURIOUS_INT = (1 << 2), /* bits 24:31 of host->flags are reserved for LLD specific flags */