|
@@ -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;
|
|
@@ -1885,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);
|
|
@@ -1912,7 +1883,7 @@ static irqreturn_t ahci_single_irq_intr(int irq, void *dev_instance)
|
|
|
|
|
|
VPRINTK("EXIT\n");
|
|
|
|
|
|
- return handled ? IRQ_WAKE_THREAD : IRQ_NONE;
|
|
|
+ return IRQ_RETVAL(handled);
|
|
|
}
|
|
|
|
|
|
unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
|
|
@@ -2324,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;
|
|
|
|
|
@@ -2486,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
|
|
@@ -2536,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);
|