[kernel/f13/master] ata-piix: Detect spurious IRQs and clear them.

Dave Jones davej at fedoraproject.org
Wed Aug 18 18:09:11 UTC 2010


commit d759c9159ed5efbd03e6847f3ef0790f1c11d7df
Author: Dave Jones <davej at redhat.com>
Date:   Wed Aug 18 14:08:58 2010 -0400

    ata-piix: Detect spurious IRQs and clear them.

 kernel.spec                                        |    7 ++
 linux-2.6-libata-ata_piix-clear-spurious-IRQ.patch |   82 ++++++++++++++++++++
 2 files changed, 89 insertions(+), 0 deletions(-)
---
diff --git a/kernel.spec b/kernel.spec
index ff5d6bc..6efb938 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -671,6 +671,8 @@ Patch800: linux-2.6-crash-driver.patch
 
 Patch900: linux-2.6-cantiga-iommu-gfx.patch
 
+Patch1000: linux-2.6-libata-ata_piix-clear-spurious-IRQ.patch
+
 # crypto/
 Patch1200: crypto-add-async-hash-testing.patch
 
@@ -1317,6 +1319,8 @@ ApplyPatch linux-2.6-crash-driver.patch
 # Cantiga chipset b0rkage
 ApplyPatch linux-2.6-cantiga-iommu-gfx.patch
 
+ApplyPatch linux-2.6-libata-ata_piix-clear-spurious-IRQ.patch
+
 # crypto/
 
 # Add async hash testing (a8f1a05)
@@ -2049,6 +2053,9 @@ fi
 
 
 %changelog
+* Wed Aug 18 2010 Dave Jones <davej at redhat.com>
+- ata-piix: Detect spurious IRQs and clear them.
+
 * Tue Aug 17 2010 Kyle McMartin <kyle at redhat.com>
 - Touch .scmversion in the kernel top level to prevent scripts/setlocalversion
   from recursing into our fedpkg git tree and trying to decide whether the
diff --git a/linux-2.6-libata-ata_piix-clear-spurious-IRQ.patch b/linux-2.6-libata-ata_piix-clear-spurious-IRQ.patch
new file mode 100644
index 0000000..351a6b2
--- /dev/null
+++ b/linux-2.6-libata-ata_piix-clear-spurious-IRQ.patch
@@ -0,0 +1,82 @@
+The DMA_IRQ bit in the bmdma status register is always set when IDEIRQ
+is asserted allowing spurious IRQ detection.  Detect spurious IRQs and
+clear them.  This protects ata_piix against nobody-cared which gets
+reported not so rarely.
+
+Signed-off-by: Tejun Heo <tj at kernel.org>
+---
+ drivers/ata/ata_piix.c |   54 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 53 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
+index 8e37be1..b438edc 100644
+--- a/drivers/ata/ata_piix.c
++++ b/drivers/ata/ata_piix.c
+@@ -922,6 +922,58 @@ static int piix_sidpr_scr_read(struct ata_link *link,
+ 	return 0;
+ }
+ 
++static irqreturn_t piix_interrupt(int irq, void *dev_instance)
++{
++	struct ata_host *host = dev_instance;
++	unsigned int i;
++	unsigned int handled = 0;
++	unsigned long flags;
++
++	spin_lock_irqsave(&host->lock, flags);
++
++	for (i = 0; i < host->n_ports; i++) {
++		struct ata_port *ap = host->ports[i];
++		struct ata_queued_cmd *qc;
++		u8 host_stat;
++
++		if (ata_port_is_dummy(ap))
++			continue;
++
++		qc = ata_qc_from_tag(ap, ap->link.active_tag);
++		if (qc && !(qc->tf.flags & ATA_TFLAG_POLLING)) {
++			handled |= ata_sff_host_intr(ap, qc);
++			continue;
++		}
++
++		/*
++		 * Control reaches here if HSM is not expecting IRQ.
++		 * If the controller is actually asserting IRQ line,
++		 * this will lead to nobody cared.  Fortuantely,
++		 * DMA_INTR of PIIX is set whenever IDEIRQ is set so
++		 * it can be used to detect spurious IRQs.  As the
++		 * driver is not expecting IRQ at all, clearing IRQ
++		 * here won't lead to loss of IRQ event.
++		 */
++		if (unlikely(!ap->ioaddr.bmdma_addr))
++			continue;
++
++		host_stat = ap->ops->bmdma_status(ap);
++		if (!(host_stat & ATA_DMA_INTR))
++			continue;
++
++		if (printk_ratelimit())
++			ata_port_printk(ap, KERN_INFO,
++					"clearing spurious IRQ\n");
++		ap->ops->sff_check_status(ap);
++		ap->ops->sff_irq_clear(ap);
++		handled |= 1;
++	}
++
++	spin_unlock_irqrestore(&host->lock, flags);
++
++	return IRQ_RETVAL(handled);
++}
++
+ static int piix_sidpr_scr_write(struct ata_link *link,
+ 				unsigned int reg, u32 val)
+ {
+@@ -1634,7 +1634,7 @@ static int __devinit piix_init_one(struc
+ 	host->flags |= ATA_HOST_PARALLEL_SCAN;
+ 
+ 	pci_set_master(pdev);
+-	return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht);
++	return ata_pci_sff_activate_host(host, piix_interrupt, &piix_sht);
+ }
+ 
+ static void piix_remove_one(struct pci_dev *pdev)


More information about the scm-commits mailing list