]> git.ipfire.org Git - ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-clear-spurious-IRQ
Move xen patchset to new version's subdir.
[ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.drivers / libata-ata_piix-clear-spurious-IRQ
diff --git a/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-clear-spurious-IRQ b/src/patches/suse-2.6.27.31/patches.drivers/libata-ata_piix-clear-spurious-IRQ
new file mode 100644 (file)
index 0000000..2282b48
--- /dev/null
@@ -0,0 +1,85 @@
+From: Tejun Heo <tj@kernel.org>
+Subject: ata_piix: detect and clear spurious IRQs
+References: bnc#445872
+
+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@kernel.org>
+Signed-off-by: Tejun Heo <teheo@suse.de>
+---
+ drivers/ata/ata_piix.c |   54 ++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 53 insertions(+), 1 deletion(-)
+
+--- a/drivers/ata/ata_piix.c
++++ b/drivers/ata/ata_piix.c
+@@ -923,6 +923,58 @@ static int piix_sidpr_scr_read(struct at
+       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)
+ {
+@@ -1543,7 +1595,7 @@ static int __devinit piix_init_one(struc
+       }
+       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 int __init piix_init(void)