summaryrefslogtreecommitdiffstats
path: root/drivers/ata/libahci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/libahci.c')
-rw-r--r--drivers/ata/libahci.c78
1 files changed, 17 insertions, 61 deletions
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 5eb61c9e63d..97683e45ab0 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -1778,16 +1778,15 @@ static void ahci_handle_port_interrupt(struct ata_port *ap,
}
}
-static void ahci_update_intr_status(struct ata_port *ap)
+static void ahci_port_intr(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_port_priv *pp = ap->private_data;
u32 status;
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
- atomic_or(status, &pp->intr_status);
+ ahci_handle_port_interrupt(ap, port_mmio, status);
}
static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance)
@@ -1808,34 +1807,6 @@ static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance)
return IRQ_HANDLED;
}
-irqreturn_t ahci_thread_fn(int irq, void *dev_instance)
-{
- struct ata_host *host = dev_instance;
- struct ahci_host_priv *hpriv = host->private_data;
- u32 irq_masked = hpriv->port_map;
- unsigned int i;
-
- for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap;
-
- if (!(irq_masked & (1 << i)))
- continue;
-
- ap = host->ports[i];
- if (ap) {
- ahci_port_thread_fn(irq, ap);
- VPRINTK("port %u\n", i);
- } else {
- VPRINTK("port %u (no irq)\n", i);
- if (ata_ratelimit())
- dev_warn(host->dev,
- "interrupt on disabled port %u\n", i);
- }
- }
-
- return IRQ_HANDLED;
-}
-
static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance)
{
struct ata_port *ap = dev_instance;
@@ -1875,6 +1846,8 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance)
irq_masked = irq_stat & hpriv->port_map;
+ spin_lock(&host->lock);
+
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap;
@@ -1883,7 +1856,7 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance)
ap = host->ports[i];
if (ap) {
- ahci_update_intr_status(ap);
+ ahci_port_intr(ap);
VPRINTK("port %u\n", i);
} else {
VPRINTK("port %u (no irq)\n", i);
@@ -1906,9 +1879,11 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance)
*/
writel(irq_stat, mmio + HOST_IRQ_STAT);
+ spin_unlock(&host->lock);
+
VPRINTK("EXIT\n");
- return handled ? IRQ_WAKE_THREAD : IRQ_NONE;
+ return IRQ_RETVAL(handled);
}
unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
@@ -2320,8 +2295,13 @@ static int ahci_port_start(struct ata_port *ap)
*/
pp->intr_mask = DEF_PORT_IRQ;
- spin_lock_init(&pp->lock);
- ap->lock = &pp->lock;
+ /*
+ * Switch to per-port locking in case each port has its own MSI vector.
+ */
+ if ((hpriv->flags & AHCI_HFLAG_MULTI_MSI)) {
+ spin_lock_init(&pp->lock);
+ ap->lock = &pp->lock;
+ }
ap->private_data = pp;
@@ -2482,31 +2462,6 @@ out_free_irqs:
return rc;
}
-static int ahci_host_activate_single_irq(struct ata_host *host, int irq,
- struct scsi_host_template *sht)
-{
- int i, rc;
-
- rc = ata_host_start(host);
- if (rc)
- return rc;
-
- rc = devm_request_threaded_irq(host->dev, irq, ahci_single_irq_intr,
- ahci_thread_fn, IRQF_SHARED,
- dev_driver_string(host->dev), host);
- if (rc)
- return rc;
-
- for (i = 0; i < host->n_ports; i++)
- ata_port_desc(host->ports[i], "irq %d", irq);
-
- rc = ata_host_register(host, sht);
- if (rc)
- devm_free_irq(host->dev, irq, host);
-
- return rc;
-}
-
/**
* ahci_host_activate - start AHCI host, request IRQs and register it
* @host: target ATA host
@@ -2532,7 +2487,8 @@ 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
- rc = ahci_host_activate_single_irq(host, irq, sht);
+ rc = ata_host_activate(host, irq, ahci_single_irq_intr,
+ IRQF_SHARED, sht);
return rc;
}
EXPORT_SYMBOL_GPL(ahci_host_activate);