aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ata/ahci.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 061817a3a0e5..5e6468a7ca4b 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1777,7 +1777,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
1777 struct ahci_host_priv *hpriv; 1777 struct ahci_host_priv *hpriv;
1778 unsigned int i, handled = 0; 1778 unsigned int i, handled = 0;
1779 void __iomem *mmio; 1779 void __iomem *mmio;
1780 u32 irq_stat; 1780 u32 irq_stat, irq_masked;
1781 1781
1782 VPRINTK("ENTER\n"); 1782 VPRINTK("ENTER\n");
1783 1783
@@ -1786,16 +1786,17 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
1786 1786
1787 /* sigh. 0xffffffff is a valid return from h/w */ 1787 /* sigh. 0xffffffff is a valid return from h/w */
1788 irq_stat = readl(mmio + HOST_IRQ_STAT); 1788 irq_stat = readl(mmio + HOST_IRQ_STAT);
1789 irq_stat &= hpriv->port_map;
1790 if (!irq_stat) 1789 if (!irq_stat)
1791 return IRQ_NONE; 1790 return IRQ_NONE;
1792 1791
1792 irq_masked = irq_stat & hpriv->port_map;
1793
1793 spin_lock(&host->lock); 1794 spin_lock(&host->lock);
1794 1795
1795 for (i = 0; i < host->n_ports; i++) { 1796 for (i = 0; i < host->n_ports; i++) {
1796 struct ata_port *ap; 1797 struct ata_port *ap;
1797 1798
1798 if (!(irq_stat & (1 << i))) 1799 if (!(irq_masked & (1 << i)))
1799 continue; 1800 continue;
1800 1801
1801 ap = host->ports[i]; 1802 ap = host->ports[i];
@@ -1812,6 +1813,15 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
1812 handled = 1; 1813 handled = 1;
1813 } 1814 }
1814 1815
1816 /* HOST_IRQ_STAT behaves as level triggered latch meaning that
1817 * it should be cleared after all the port events are cleared;
1818 * otherwise, it will raise a spurious interrupt after each
1819 * valid one. Please read section 10.6.2 of ahci 1.1 for more
1820 * information.
1821 *
1822 * Also, use the unmasked value to clear interrupt as spurious
1823 * pending event on a dummy port might cause screaming IRQ.
1824 */
1815 writel(irq_stat, mmio + HOST_IRQ_STAT); 1825 writel(irq_stat, mmio + HOST_IRQ_STAT);
1816 1826
1817 spin_unlock(&host->lock); 1827 spin_unlock(&host->lock);