]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mmc: core: Prevent processing SDIO IRQs when the card is suspended
authorUlf Hansson <ulf.hansson@linaro.org>
Tue, 18 Jun 2019 12:05:17 +0000 (14:05 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 25 Jun 2019 03:35:53 +0000 (11:35 +0800)
commit 83293386bc95cf5e9f0c0175794455835bd1cb4a upstream.

Processing of SDIO IRQs must obviously be prevented while the card is
system suspended, otherwise we may end up trying to communicate with an
uninitialized SDIO card.

Reports throughout the years shows that this is not only a theoretical
problem, but a real issue. So, let's finally fix this problem, by keeping
track of the state for the card and bail out before processing the SDIO
IRQ, in case the card is suspended.

Cc: stable@vger.kernel.org
Reported-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_irq.c

index d8e17ea6126de8339beddd776702e5aa3c0691d5..0aa99694b9379899bfe4ee86a7ca2c9b0e44cc72 100644 (file)
@@ -934,6 +934,10 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host)
  */
 static int mmc_sdio_suspend(struct mmc_host *host)
 {
+       /* Prevent processing of SDIO IRQs in suspended state. */
+       mmc_card_set_suspended(host->card);
+       cancel_delayed_work_sync(&host->sdio_irq_work);
+
        mmc_claim_host(host);
 
        if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host))
@@ -982,13 +986,20 @@ static int mmc_sdio_resume(struct mmc_host *host)
                err = sdio_enable_4bit_bus(host->card);
        }
 
-       if (!err && host->sdio_irqs) {
+       if (err)
+               goto out;
+
+       /* Allow SDIO IRQs to be processed again. */
+       mmc_card_clr_suspended(host->card);
+
+       if (host->sdio_irqs) {
                if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD))
                        wake_up_process(host->sdio_irq_thread);
                else if (host->caps & MMC_CAP_SDIO_IRQ)
                        host->ops->enable_sdio_irq(host, 1);
        }
 
+out:
        mmc_release_host(host);
 
        host->pm_flags &= ~MMC_PM_KEEP_POWER;
index 7ca7b99413f0d98bc5cb9f48bb68dc4a77b78f6f..b299a24d33f96592e36c7463f80d601811c709d2 100644 (file)
@@ -38,6 +38,10 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
        unsigned char pending;
        struct sdio_func *func;
 
+       /* Don't process SDIO IRQs if the card is suspended. */
+       if (mmc_card_suspended(card))
+               return 0;
+
        /*
         * Optimization, if there is only 1 function interrupt registered
         * and we know an IRQ was signaled then call irq handler directly.