diff --git a/kernel.spec b/kernel.spec index ff5d6bcb0..6efb9389e 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 +- ata-piix: Detect spurious IRQs and clear them. + * Tue Aug 17 2010 Kyle McMartin - 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 000000000..351a6b297 --- /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 +--- + 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)