}
}
-static void ahci_port_intr(struct ata_port *ap)
+static void ahci_update_intr_status(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);
- ahci_handle_port_interrupt(ap, port_mmio, status);
+ atomic_or(status, &pp->intr_status);
}
static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance)
struct ata_port *ap = dev_instance;
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
- unsigned long flags;
u32 status;
- spin_lock_irqsave(&ap->host->lock, flags);
- status = pp->intr_status;
- if (status)
- pp->intr_status = 0;
- spin_unlock_irqrestore(&ap->host->lock, flags);
+ status = atomic_xchg(&pp->intr_status, 0);
+ if (!status)
+ return IRQ_NONE;
spin_lock_bh(ap->lock);
ahci_handle_port_interrupt(ap, port_mmio, status);
return IRQ_HANDLED;
}
-static void ahci_update_intr_status(struct ata_port *ap)
+irqreturn_t ahci_thread_fn(int irq, void *dev_instance)
{
- 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);
-
- pp->intr_status |= status;
-}
-
-static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance)
-{
- struct ata_port *ap_this = dev_instance;
- struct ahci_port_priv *pp = ap_this->private_data;
- struct ata_host *host = ap_this->host;
+ struct ata_host *host = dev_instance;
struct ahci_host_priv *hpriv = host->private_data;
- void __iomem *mmio = hpriv->mmio;
+ u32 irq_masked = hpriv->port_map;
unsigned int i;
- u32 irq_stat, irq_masked;
-
- VPRINTK("ENTER\n");
-
- spin_lock(&host->lock);
-
- irq_stat = readl(mmio + HOST_IRQ_STAT);
-
- if (!irq_stat) {
- u32 status = pp->intr_status;
-
- spin_unlock(&host->lock);
-
- VPRINTK("EXIT\n");
-
- return status ? IRQ_WAKE_THREAD : IRQ_NONE;
- }
-
- irq_masked = irq_stat & hpriv->port_map;
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap;
ap = host->ports[i];
if (ap) {
- ahci_update_intr_status(ap);
+ ahci_port_thread_fn(irq, ap);
VPRINTK("port %u\n", i);
} else {
VPRINTK("port %u (no irq)\n", i);
}
}
- writel(irq_stat, mmio + HOST_IRQ_STAT);
+ return IRQ_HANDLED;
+}
- spin_unlock(&host->lock);
+static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance)
+{
+ struct ata_port *ap = dev_instance;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_port_priv *pp = ap->private_data;
+ u32 status;
+
+ VPRINTK("ENTER\n");
+
+ status = readl(port_mmio + PORT_IRQ_STAT);
+ writel(status, port_mmio + PORT_IRQ_STAT);
+
+ atomic_or(status, &pp->intr_status);
VPRINTK("EXIT\n");
irq_masked = irq_stat & hpriv->port_map;
- spin_lock(&host->lock);
-
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap;
ap = host->ports[i];
if (ap) {
- ahci_port_intr(ap);
+ ahci_update_intr_status(ap);
VPRINTK("port %u\n", i);
} else {
VPRINTK("port %u (no irq)\n", i);
*/
writel(irq_stat, mmio + HOST_IRQ_STAT);
- spin_unlock(&host->lock);
-
VPRINTK("EXIT\n");
- return IRQ_RETVAL(handled);
+ return handled ? IRQ_WAKE_THREAD : IRQ_NONE;
}
unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
*/
pp->intr_mask = DEF_PORT_IRQ;
- /*
- * 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;
- }
+ spin_lock_init(&pp->lock);
+ ap->lock = &pp->lock;
ap->private_data = pp;
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
if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
rc = ahci_host_activate_multi_irqs(host, irq, sht);
else
- rc = ata_host_activate(host, irq, ahci_single_irq_intr,
- IRQF_SHARED, sht);
+ rc = ahci_host_activate_single_irq(host, irq, sht);
return rc;
}
EXPORT_SYMBOL_GPL(ahci_host_activate);