}
 }
 
-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)
        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;
 
                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);
 
        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);