libahci: Add support to handle HOST_IRQ_STAT as edge trigger latch.
authorSuman Tripathi <stripathi@apm.com>
Tue, 5 May 2015 19:21:11 +0000 (00:51 +0530)
committerTejun Heo <tj@kernel.org>
Sun, 10 May 2015 15:52:44 +0000 (11:52 -0400)
This patch adds the support to handle HOST_IRQ_STAT as edge trigger
latch.

Signed-off-by: Suman Tripathi <stripathi@apm.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
drivers/ata/ahci.h
drivers/ata/libahci.c

index 71262e08648e72d786cf8dca1f6bb338bee4375c..f4429600e2bfb8d6f9dd3962c2dfa99ac9bd55f4 100644 (file)
@@ -238,6 +238,8 @@ enum {
        AHCI_HFLAG_MULTI_MSI            = (1 << 16), /* multiple PCI MSIs */
        AHCI_HFLAG_NO_DEVSLP            = (1 << 17), /* no device sleep */
        AHCI_HFLAG_NO_FBS               = (1 << 18), /* no FBS */
+       AHCI_HFLAG_EDGE_IRQ             = (1 << 19), /* HOST_IRQ_STAT behaves as
+                                                       Edge Triggered */
 
        /* ap->flags bits */
 
index aa89c8eecd7653a7107235c84bde0ccdd25ed71b..1add5baec58483c1c2ba6870962a79ed7aff7772 100644 (file)
@@ -1853,6 +1853,43 @@ static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
        return handled;
 }
 
+static irqreturn_t ahci_single_edge_irq_intr(int irq, void *dev_instance)
+{
+       struct ata_host *host = dev_instance;
+       struct ahci_host_priv *hpriv;
+       unsigned int rc = 0;
+       void __iomem *mmio;
+       u32 irq_stat, irq_masked;
+
+       VPRINTK("ENTER\n");
+
+       hpriv = host->private_data;
+       mmio = hpriv->mmio;
+
+       /* sigh.  0xffffffff is a valid return from h/w */
+       irq_stat = readl(mmio + HOST_IRQ_STAT);
+       if (!irq_stat)
+               return IRQ_NONE;
+
+       irq_masked = irq_stat & hpriv->port_map;
+
+       spin_lock(&host->lock);
+
+       /*
+        * HOST_IRQ_STAT behaves as edge triggered latch meaning that
+        * it should be cleared before all the port events are cleared.
+        */
+       writel(irq_stat, mmio + HOST_IRQ_STAT);
+
+       rc = ahci_handle_port_intr(host, irq_masked);
+
+       spin_unlock(&host->lock);
+
+       VPRINTK("EXIT\n");
+
+       return IRQ_RETVAL(rc);
+}
+
 static irqreturn_t ahci_single_level_irq_intr(int irq, void *dev_instance)
 {
        struct ata_host *host = dev_instance;
@@ -2495,6 +2532,9 @@ int ahci_host_activate(struct ata_host *host, int irq,
 
        if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
                rc = ahci_host_activate_multi_irqs(host, irq, sht);
+       else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ)
+               rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr,
+                                      IRQF_SHARED, sht);
        else
                rc = ata_host_activate(host, irq, ahci_single_level_irq_intr,
                                       IRQF_SHARED, sht);