MLK-12360-1 mmc: sdhci: add sdio thread irq support
authorDong Aisheng <aisheng.dong@nxp.com>
Tue, 26 Jan 2016 14:20:08 +0000 (22:20 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:50:03 +0000 (14:50 -0500)
Some special SDIO devices like Broadcom WiFi driver will keep handling
SDIO irq even after the driver is already suspended.
This weird behavior will block the MMC host suspend during its irq
synchronize operation in free_irq(), then the system suspend is blocked
too and hanged.

We add back sdio thread irq support for such WiFi driver to handle
SDIO irqs since the sdio thread is kernel thread which does not
block the process freeze operation during suspend.

Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
drivers/mmc/host/sdhci.c

index dc4f170..d215d3b 100644 (file)
@@ -2661,6 +2661,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
        struct sdhci_host *host = dev_id;
        u32 intmask, mask, unexpected = 0;
        int max_loops = 16;
+       int cardint = 0;
 
        spin_lock(&host->lock);
 
@@ -2729,9 +2730,13 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 
                if ((intmask & SDHCI_INT_CARD_INT) &&
                    (host->ier & SDHCI_INT_CARD_INT)) {
-                       sdhci_enable_sdio_irq_nolock(host, false);
-                       host->thread_isr |= SDHCI_INT_CARD_INT;
-                       result = IRQ_WAKE_THREAD;
+                       if (host->mmc->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD) {
+                               sdhci_enable_sdio_irq_nolock(host, false);
+                               host->thread_isr |= SDHCI_INT_CARD_INT;
+                               result = IRQ_WAKE_THREAD;
+                       } else {
+                               cardint = 1;
+                       }
                }
 
                intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
@@ -2758,6 +2763,9 @@ out:
                sdhci_dumpregs(host);
        }
 
+       if (cardint && host->mmc->sdio_irqs)
+               mmc_signal_sdio_irq(host->mmc);
+
        return result;
 }
 
@@ -2780,12 +2788,13 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
        }
 
        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);
+               if (host->mmc->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD) {
+                       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;