OSDN Git Service

mmc: host: Cancel clock gating work in suspend
authorSayali Lokhande <sayalil@codeaurora.org>
Mon, 19 Feb 2018 11:08:26 +0000 (16:38 +0530)
committerGerrit - the friendly Code Review server <code-review@localhost>
Tue, 19 Mar 2019 04:15:38 +0000 (21:15 -0700)
In some scenarios, it is observed that mmc clock gating
work is racing with pm suspend resulting in unclocked
register access.

Sequence of events:
1) System is going to suspend (PM_SUSPEND_PREPARE)
2) Sd card is inserted and mmc_power_up() is called
as part of mmc_sd_detect.
3) mmc_power_up() released clocks and clock gate work
is scheduled.
4) As part of PM suspend clocks are disabled.
5) Clock gate work(scheduled at step 3) kicks in now
after suspend and unclocked register access happens in
sdhci_set_bus_width() function.

Logs:
mmc1: Enter mode PM_SUSPEND_PREPARE
mmc_sd_detect(mmc1): Re-init card success in mmc_sd_detect
    => mmc_power_up (clocks released here)
mmc1: Enter mode PM_POST_SUSPEND
mmc1: sdhci_msm_runtime_suspend: Enter
mmc1: sdhci_msm_runtime_suspend: Exit
mmc1: Enter mode PM_SUSPEND_PREPARE
mmc1: mmc_bus_suspend: Enter
mmc1: mmc_bus_suspend: Exit 0
mmc1: sdhci_msm_suspend: Enter
mmc1: sdhci_msm_suspend: already runtime suspended
mmc1: sdhci_msm_disable_controller_clock: disabled clock
    => PM_SUSPEND disabled clocks
mmc1: sdhci_msm_suspend: Exit ret: 0
mmc_host_clk_gate_delayed: mmc1: Enter
mmc_host_clk_gate_delayed: mmc1: calling gate_clock..
<>
Unhandled fault: external abort
Workqueue: events mmc_host_clk_gate_work
PC is at sdhci_set_bus_width+0x2c/0xb4

To fix this unclocked access, cancel any clock gating work
scheduled by mmc_host_clk_release() before turning off clocks
in suspend.

Change-Id: I1165ad2c5a1eb52abf18fef12667e93c947ae417
Signed-off-by: Sayali Lokhande <sayalil@codeaurora.org>
drivers/mmc/host/sdhci-msm.c

index 0468ea4..a7bd93f 100644 (file)
@@ -5110,6 +5110,7 @@ static int sdhci_msm_suspend(struct device *dev)
        struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_msm_host *msm_host = pltfm_host->priv;
+       struct mmc_host *mmc = host->mmc;
        int ret = 0;
        int sdio_cfg = 0;
        ktime_t start = ktime_get();
@@ -5125,6 +5126,8 @@ static int sdhci_msm_suspend(struct device *dev)
        }
        ret = sdhci_msm_runtime_suspend(dev);
 out:
+       /* cancel any clock gating work scheduled by mmc_host_clk_release() */
+       cancel_delayed_work_sync(&mmc->clk_gate_work);
        sdhci_msm_disable_controller_clock(host);
        if (host->mmc->card && mmc_card_sdio(host->mmc->card)) {
                sdio_cfg = sdhci_msm_cfg_sdio_wakeup(host, true);