[PATCH v2] mmc: sdhci-esdhc-imx: fix abort due to missing runtime PM

From: Stefan Agner
Date: Mon Mar 30 2015 - 07:37:25 EST


When entering suspend while the device is in runtime PM, the
sdhci_(suspend|resume)_host function are called with disabled clocks.
Since this functions access the SDHC host registers, this leads to an
external abort on Vybrid SoC:

[ 37.772967] Unhandled fault: imprecise external abort (0x1c06) at 0x76f5f000
[ 37.780304] Internal error: : 1c06 [#1] ARM
[ 37.784670] Modules linked in:
[ 37.787908] CPU: 0 PID: 428 Comm: sh Not tainted 3.18.0-rc5-00119-geefd097-dirty #1540
[ 37.796142] task: 8e246c00 ti: 8ca6c000 task.ti: 8ca6c000
[ 37.801785] PC is at esdhc_writel_le+0x40/0xec
[ 37.806431] LR is at sdhci_set_card_detection+0xe0/0xe4
[ 37.811877] pc : [<803f0584>] lr : [<803eaaa0>] psr: 400f0013
[ 37.811877] sp : 8ca6dd28 ip : 00000001 fp : 8ca6dd3c
[ 37.823766] r10: 807a233c r9 : 00000000 r8 : 8e8b7210
[ 37.829194] r7 : 802d8a08 r6 : 8082e928 r5 : 00000000 r4 : 00000002
[ 37.835974] r3 : 8ea34e90 r2 : 00000038 r1 : 00000000 r0 : 8ea32ac0
...

Clocks need to be enabled to access the registers. Fix the issue by
add driver specific implementation of suspend/resume functions which
take care of clocks using runtime PM API.

Signed-off-by: Stefan Agner <stefan@xxxxxxxx>
---
The first version of this patch was part of a patchset sent back in
december. While the second patch of the patchset back then is invalid,
this fix is required to avoid the abort when switching into suspend
mode on Vybrid SoC.

During review of this patch I realized that my proposed solution to
fix this in the suspend/resume functions in sdhci-pltfm.c is not a
good idea since a lot of drivers use this functions without using the
runtime PM APIs.

Changes since v1:
- Create new sdhci_esdhc_(suspend|resume) functions in favor of adding a
hard requirement for runtime PM on SDHC platform implementations

drivers/mmc/host/sdhci-esdhc-imx.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 10ef824..84b3365 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -1119,6 +1119,32 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
}

#ifdef CONFIG_PM
+static int sdhci_esdhc_suspend(struct device *dev)
+{
+ int ret;
+ struct sdhci_host *host = dev_get_drvdata(dev);
+
+ pm_runtime_get_sync(dev);
+ ret = sdhci_suspend_host(host);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
+}
+
+static int sdhci_esdhc_resume(struct device *dev)
+{
+ int ret;
+ struct sdhci_host *host = dev_get_drvdata(dev);
+
+ pm_runtime_get_sync(dev);
+ ret = sdhci_resume_host(host);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
+}
+
static int sdhci_esdhc_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
@@ -1154,7 +1180,7 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
#endif

static const struct dev_pm_ops sdhci_esdhc_pmops = {
- SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_suspend, sdhci_pltfm_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(sdhci_esdhc_suspend, sdhci_esdhc_resume)
SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
sdhci_esdhc_runtime_resume, NULL)
};
--
2.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/