static irqreturn_t sdhci_irq(int irq, void *dev_id)
 {
-       irqreturn_t result;
+       irqreturn_t result = IRQ_NONE;
        struct sdhci_host *host = dev_id;
        u32 intmask, mask, unexpected = 0;
-       int cardint = 0, max_loops = 16;
+       int max_loops = 16;
 
        spin_lock(&host->lock);
 
                        pr_err("%s: Card is consuming too much power!\n",
                                mmc_hostname(host->mmc));
 
-               if (intmask & SDHCI_INT_CARD_INT)
-                       cardint = 1;
+               if (intmask & SDHCI_INT_CARD_INT) {
+                       sdhci_enable_sdio_irq_nolock(host, false);
+                       host->thread_isr |= SDHCI_INT_CARD_INT;
+                       result = IRQ_WAKE_THREAD;
+               }
 
                intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
                             SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
                        sdhci_writel(host, intmask, SDHCI_INT_STATUS);
                }
 
-               result = IRQ_HANDLED;
+               if (result == IRQ_NONE)
+                       result = IRQ_HANDLED;
 
                intmask = sdhci_readl(host, SDHCI_INT_STATUS);
-
-               /*
-                * If we know we'll call the driver to signal SDIO IRQ,
-                * disregard further indications of Card Interrupt in
-                * the status to avoid a needless loop.
-                */
-               if (cardint)
-                       intmask &= ~SDHCI_INT_CARD_INT;
        } while (intmask && --max_loops);
 out:
        spin_unlock(&host->lock);
                           mmc_hostname(host->mmc), unexpected);
                sdhci_dumpregs(host);
        }
-       /*
-        * We have to delay this as it calls back into the driver.
-        */
-       if (cardint)
-               mmc_signal_sdio_irq(host->mmc);
 
        return result;
 }
 
+static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
+{
+       struct sdhci_host *host = dev_id;
+       unsigned long flags;
+       u32 isr;
+
+       spin_lock_irqsave(&host->lock, flags);
+       isr = host->thread_isr;
+       host->thread_isr = 0;
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       if (isr & SDHCI_INT_CARD_INT) {
+               sdio_run_irqs(host->mmc);
+
+               spin_lock_irqsave(&host->lock, flags);
+               if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
+                       sdhci_enable_sdio_irq_nolock(host, true);
+               spin_unlock_irqrestore(&host->lock, flags);
+       }
+
+       return isr ? IRQ_HANDLED : IRQ_NONE;
+}
+
 /*****************************************************************************\
  *                                                                           *
  * Suspend/resume                                                            *
        }
 
        if (!device_may_wakeup(mmc_dev(host->mmc))) {
-               ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-                                 mmc_hostname(host->mmc), host);
+               ret = request_threaded_irq(host->irq, sdhci_irq,
+                                          sdhci_thread_irq, IRQF_SHARED,
+                                          mmc_hostname(host->mmc), host);
                if (ret)
                        return ret;
        } else {
        sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
        spin_unlock_irqrestore(&host->lock, flags);
 
-       synchronize_irq(host->irq);
+       synchronize_hardirq(host->irq);
 
        spin_lock_irqsave(&host->lock, flags);
        host->runtime_suspended = true;
        mmc->max_busy_timeout = (1 << 27) / host->timeout_clk;
 
        mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
+       mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
 
        if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
                host->flags |= SDHCI_AUTO_CMD12;
 
        sdhci_init(host, 0);
 
-       ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-               mmc_hostname(mmc), host);
+       ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq,
+                                  IRQF_SHARED, mmc_hostname(mmc), host);
        if (ret) {
                pr_err("%s: Failed to request IRQ %d: %d\n",
                       mmc_hostname(mmc), host->irq, ret);