All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM
@ 2015-05-21  7:15 ` Stefan Agner
  0 siblings, 0 replies; 14+ messages in thread
From: Stefan Agner @ 2015-05-21  7:15 UTC (permalink / raw)
  To: ulf.hansson
  Cc: gregory.clement, zhangfei.gao, jszhang, chris, anton, b29396,
	shawn.guo, linux-mmc, linux-arm-kernel, linux-kernel, stefan

When using i.MX ESDHC driver, while 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 runtime PM enabled pltfm implementation of suspend/resume which
take care of clocks by using the runtime PM API properly.

Signed-off-by: Stefan Agner <stefan@agner.ch>
---
Changes since v2:
- Implement a generic pltfm suspend/resume function instead of a local
  function in sdhci-esdhc-imx.c
- Convert sdhci-pxav3 to use the runtime PM enabled pltfm suspend/resume
  function too

 drivers/mmc/host/sdhci-esdhc-imx.c |  2 +-
 drivers/mmc/host/sdhci-pltfm.c     | 36 ++++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-pltfm.h     |  2 ++
 3 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 82f512d..7b7b3a3 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -1132,7 +1132,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_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
 	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
 				sdhci_esdhc_runtime_resume, NULL)
 };
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index a207f5a..38c03cd 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -31,6 +31,7 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/pm_runtime.h>
 #ifdef CONFIG_PPC
 #include <asm/machdep.h>
 #endif
@@ -256,6 +257,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
 	.resume		= sdhci_pltfm_resume,
 };
 EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
+
+int sdhci_pltfm_rpm_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);
+	if (ret)
+		return ret;
+
+	return pm_runtime_force_suspend(dev);
+}
+EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
+
+int sdhci_pltfm_rpm_resume(struct device *dev)
+{
+	int ret;
+	struct sdhci_host *host = dev_get_drvdata(dev);
+
+	ret = pm_runtime_force_resume(dev);
+
+	if (ret)
+		return ret;
+
+	pm_runtime_get_sync(dev);
+	ret = sdhci_resume_host(host);
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
 #endif	/* CONFIG_PM */
 
 static int __init sdhci_pltfm_drv_init(void)
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 04bc248..ac5f6ea 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -114,6 +114,8 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
 extern int sdhci_pltfm_suspend(struct device *dev);
 extern int sdhci_pltfm_resume(struct device *dev);
 extern const struct dev_pm_ops sdhci_pltfm_pmops;
+extern int sdhci_pltfm_rpm_suspend(struct device *dev);
+extern int sdhci_pltfm_rpm_resume(struct device *dev);
 #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
 #else
 #define SDHCI_PLTFM_PMOPS NULL
-- 
2.4.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM
@ 2015-05-21  7:15 ` Stefan Agner
  0 siblings, 0 replies; 14+ messages in thread
From: Stefan Agner @ 2015-05-21  7:15 UTC (permalink / raw)
  To: linux-arm-kernel

When using i.MX ESDHC driver, while 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 runtime PM enabled pltfm implementation of suspend/resume which
take care of clocks by using the runtime PM API properly.

Signed-off-by: Stefan Agner <stefan@agner.ch>
---
Changes since v2:
- Implement a generic pltfm suspend/resume function instead of a local
  function in sdhci-esdhc-imx.c
- Convert sdhci-pxav3 to use the runtime PM enabled pltfm suspend/resume
  function too

 drivers/mmc/host/sdhci-esdhc-imx.c |  2 +-
 drivers/mmc/host/sdhci-pltfm.c     | 36 ++++++++++++++++++++++++++++++++++++
 drivers/mmc/host/sdhci-pltfm.h     |  2 ++
 3 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 82f512d..7b7b3a3 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -1132,7 +1132,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_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
 	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
 				sdhci_esdhc_runtime_resume, NULL)
 };
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index a207f5a..38c03cd 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -31,6 +31,7 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/pm_runtime.h>
 #ifdef CONFIG_PPC
 #include <asm/machdep.h>
 #endif
@@ -256,6 +257,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
 	.resume		= sdhci_pltfm_resume,
 };
 EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
+
+int sdhci_pltfm_rpm_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);
+	if (ret)
+		return ret;
+
+	return pm_runtime_force_suspend(dev);
+}
+EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
+
+int sdhci_pltfm_rpm_resume(struct device *dev)
+{
+	int ret;
+	struct sdhci_host *host = dev_get_drvdata(dev);
+
+	ret = pm_runtime_force_resume(dev);
+
+	if (ret)
+		return ret;
+
+	pm_runtime_get_sync(dev);
+	ret = sdhci_resume_host(host);
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
 #endif	/* CONFIG_PM */
 
 static int __init sdhci_pltfm_drv_init(void)
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 04bc248..ac5f6ea 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -114,6 +114,8 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
 extern int sdhci_pltfm_suspend(struct device *dev);
 extern int sdhci_pltfm_resume(struct device *dev);
 extern const struct dev_pm_ops sdhci_pltfm_pmops;
+extern int sdhci_pltfm_rpm_suspend(struct device *dev);
+extern int sdhci_pltfm_rpm_resume(struct device *dev);
 #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
 #else
 #define SDHCI_PLTFM_PMOPS NULL
-- 
2.4.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v3 2/2] mmc: sdhci-pxav3: use runtime_pm enabled pltfm suspend/resume
  2015-05-21  7:15 ` Stefan Agner
@ 2015-05-21  7:15   ` Stefan Agner
  -1 siblings, 0 replies; 14+ messages in thread
From: Stefan Agner @ 2015-05-21  7:15 UTC (permalink / raw)
  To: ulf.hansson
  Cc: gregory.clement, zhangfei.gao, jszhang, chris, anton, b29396,
	shawn.guo, linux-mmc, linux-arm-kernel, linux-kernel, stefan

Use the runtime_pm enabled platform suspend/resume functions.

Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 drivers/mmc/host/sdhci-pxav3.c | 30 +-----------------------------
 1 file changed, 1 insertion(+), 29 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index b5103a2..5ac4030 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -501,34 +501,6 @@ static int sdhci_pxav3_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int sdhci_pxav3_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_pxav3_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;
-}
-#endif
-
 #ifdef CONFIG_PM
 static int sdhci_pxav3_runtime_suspend(struct device *dev)
 {
@@ -564,7 +536,7 @@ static int sdhci_pxav3_runtime_resume(struct device *dev)
 
 #ifdef CONFIG_PM
 static const struct dev_pm_ops sdhci_pxav3_pmops = {
-	SET_SYSTEM_SLEEP_PM_OPS(sdhci_pxav3_suspend, sdhci_pxav3_resume)
+	SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
 	SET_RUNTIME_PM_OPS(sdhci_pxav3_runtime_suspend,
 		sdhci_pxav3_runtime_resume, NULL)
 };
-- 
2.4.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v3 2/2] mmc: sdhci-pxav3: use runtime_pm enabled pltfm suspend/resume
@ 2015-05-21  7:15   ` Stefan Agner
  0 siblings, 0 replies; 14+ messages in thread
From: Stefan Agner @ 2015-05-21  7:15 UTC (permalink / raw)
  To: linux-arm-kernel

Use the runtime_pm enabled platform suspend/resume functions.

Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 drivers/mmc/host/sdhci-pxav3.c | 30 +-----------------------------
 1 file changed, 1 insertion(+), 29 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index b5103a2..5ac4030 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -501,34 +501,6 @@ static int sdhci_pxav3_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int sdhci_pxav3_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_pxav3_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;
-}
-#endif
-
 #ifdef CONFIG_PM
 static int sdhci_pxav3_runtime_suspend(struct device *dev)
 {
@@ -564,7 +536,7 @@ static int sdhci_pxav3_runtime_resume(struct device *dev)
 
 #ifdef CONFIG_PM
 static const struct dev_pm_ops sdhci_pxav3_pmops = {
-	SET_SYSTEM_SLEEP_PM_OPS(sdhci_pxav3_suspend, sdhci_pxav3_resume)
+	SET_SYSTEM_SLEEP_PM_OPS(sdhci_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
 	SET_RUNTIME_PM_OPS(sdhci_pxav3_runtime_suspend,
 		sdhci_pxav3_runtime_resume, NULL)
 };
-- 
2.4.1

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM
  2015-05-21  7:15 ` Stefan Agner
  (?)
@ 2015-05-27 10:05   ` Dong Aisheng
  -1 siblings, 0 replies; 14+ messages in thread
From: Dong Aisheng @ 2015-05-27 10:05 UTC (permalink / raw)
  To: Stefan Agner
  Cc: ulf.hansson, gregory.clement, zhangfei.gao, jszhang, chris,
	anton, shawn.guo, linux-mmc, linux-arm-kernel, linux-kernel

On Thu, May 21, 2015 at 09:15:03AM +0200, Stefan Agner wrote:
> When using i.MX ESDHC driver, while 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 runtime PM enabled pltfm implementation of suspend/resume which
> take care of clocks by using the runtime PM API properly.
> 
> Signed-off-by: Stefan Agner <stefan@agner.ch>
> ---
> Changes since v2:
> - Implement a generic pltfm suspend/resume function instead of a local
>   function in sdhci-esdhc-imx.c
> - Convert sdhci-pxav3 to use the runtime PM enabled pltfm suspend/resume
>   function too
> 
>  drivers/mmc/host/sdhci-esdhc-imx.c |  2 +-
>  drivers/mmc/host/sdhci-pltfm.c     | 36 ++++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-pltfm.h     |  2 ++
>  3 files changed, 39 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index 82f512d..7b7b3a3 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -1132,7 +1132,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_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
>  	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
>  				sdhci_esdhc_runtime_resume, NULL)
>  };
> diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
> index a207f5a..38c03cd 100644
> --- a/drivers/mmc/host/sdhci-pltfm.c
> +++ b/drivers/mmc/host/sdhci-pltfm.c
> @@ -31,6 +31,7 @@
>  #include <linux/err.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/pm_runtime.h>
>  #ifdef CONFIG_PPC
>  #include <asm/machdep.h>
>  #endif
> @@ -256,6 +257,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
>  	.resume		= sdhci_pltfm_resume,
>  };
>  EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
> +
> +int sdhci_pltfm_rpm_suspend(struct device *dev)

Why invent a new API?
Can't put into sdhci_pltfm_suspend?

Regards
Dong Aisheng

> +{
> +	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);
> +	if (ret)
> +		return ret;
> +
> +	return pm_runtime_force_suspend(dev);
> +}
> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
> +
> +int sdhci_pltfm_rpm_resume(struct device *dev)
> +{
> +	int ret;
> +	struct sdhci_host *host = dev_get_drvdata(dev);
> +
> +	ret = pm_runtime_force_resume(dev);
> +
> +	if (ret)
> +		return ret;
> +
> +	pm_runtime_get_sync(dev);
> +	ret = sdhci_resume_host(host);
> +	pm_runtime_mark_last_busy(dev);
> +	pm_runtime_put_autosuspend(dev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
>  #endif	/* CONFIG_PM */
>  
>  static int __init sdhci_pltfm_drv_init(void)
> diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
> index 04bc248..ac5f6ea 100644
> --- a/drivers/mmc/host/sdhci-pltfm.h
> +++ b/drivers/mmc/host/sdhci-pltfm.h
> @@ -114,6 +114,8 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
>  extern int sdhci_pltfm_suspend(struct device *dev);
>  extern int sdhci_pltfm_resume(struct device *dev);
>  extern const struct dev_pm_ops sdhci_pltfm_pmops;
> +extern int sdhci_pltfm_rpm_suspend(struct device *dev);
> +extern int sdhci_pltfm_rpm_resume(struct device *dev);
>  #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
>  #else
>  #define SDHCI_PLTFM_PMOPS NULL
> -- 
> 2.4.1
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM
@ 2015-05-27 10:05   ` Dong Aisheng
  0 siblings, 0 replies; 14+ messages in thread
From: Dong Aisheng @ 2015-05-27 10:05 UTC (permalink / raw)
  To: Stefan Agner
  Cc: ulf.hansson, gregory.clement, zhangfei.gao, jszhang, chris,
	anton, shawn.guo, linux-mmc, linux-arm-kernel, linux-kernel

On Thu, May 21, 2015 at 09:15:03AM +0200, Stefan Agner wrote:
> When using i.MX ESDHC driver, while 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 runtime PM enabled pltfm implementation of suspend/resume which
> take care of clocks by using the runtime PM API properly.
> 
> Signed-off-by: Stefan Agner <stefan@agner.ch>
> ---
> Changes since v2:
> - Implement a generic pltfm suspend/resume function instead of a local
>   function in sdhci-esdhc-imx.c
> - Convert sdhci-pxav3 to use the runtime PM enabled pltfm suspend/resume
>   function too
> 
>  drivers/mmc/host/sdhci-esdhc-imx.c |  2 +-
>  drivers/mmc/host/sdhci-pltfm.c     | 36 ++++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-pltfm.h     |  2 ++
>  3 files changed, 39 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index 82f512d..7b7b3a3 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -1132,7 +1132,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_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
>  	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
>  				sdhci_esdhc_runtime_resume, NULL)
>  };
> diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
> index a207f5a..38c03cd 100644
> --- a/drivers/mmc/host/sdhci-pltfm.c
> +++ b/drivers/mmc/host/sdhci-pltfm.c
> @@ -31,6 +31,7 @@
>  #include <linux/err.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/pm_runtime.h>
>  #ifdef CONFIG_PPC
>  #include <asm/machdep.h>
>  #endif
> @@ -256,6 +257,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
>  	.resume		= sdhci_pltfm_resume,
>  };
>  EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
> +
> +int sdhci_pltfm_rpm_suspend(struct device *dev)

Why invent a new API?
Can't put into sdhci_pltfm_suspend?

Regards
Dong Aisheng

> +{
> +	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);
> +	if (ret)
> +		return ret;
> +
> +	return pm_runtime_force_suspend(dev);
> +}
> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
> +
> +int sdhci_pltfm_rpm_resume(struct device *dev)
> +{
> +	int ret;
> +	struct sdhci_host *host = dev_get_drvdata(dev);
> +
> +	ret = pm_runtime_force_resume(dev);
> +
> +	if (ret)
> +		return ret;
> +
> +	pm_runtime_get_sync(dev);
> +	ret = sdhci_resume_host(host);
> +	pm_runtime_mark_last_busy(dev);
> +	pm_runtime_put_autosuspend(dev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
>  #endif	/* CONFIG_PM */
>  
>  static int __init sdhci_pltfm_drv_init(void)
> diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
> index 04bc248..ac5f6ea 100644
> --- a/drivers/mmc/host/sdhci-pltfm.h
> +++ b/drivers/mmc/host/sdhci-pltfm.h
> @@ -114,6 +114,8 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
>  extern int sdhci_pltfm_suspend(struct device *dev);
>  extern int sdhci_pltfm_resume(struct device *dev);
>  extern const struct dev_pm_ops sdhci_pltfm_pmops;
> +extern int sdhci_pltfm_rpm_suspend(struct device *dev);
> +extern int sdhci_pltfm_rpm_resume(struct device *dev);
>  #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
>  #else
>  #define SDHCI_PLTFM_PMOPS NULL
> -- 
> 2.4.1
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM
@ 2015-05-27 10:05   ` Dong Aisheng
  0 siblings, 0 replies; 14+ messages in thread
From: Dong Aisheng @ 2015-05-27 10:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 21, 2015 at 09:15:03AM +0200, Stefan Agner wrote:
> When using i.MX ESDHC driver, while 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 runtime PM enabled pltfm implementation of suspend/resume which
> take care of clocks by using the runtime PM API properly.
> 
> Signed-off-by: Stefan Agner <stefan@agner.ch>
> ---
> Changes since v2:
> - Implement a generic pltfm suspend/resume function instead of a local
>   function in sdhci-esdhc-imx.c
> - Convert sdhci-pxav3 to use the runtime PM enabled pltfm suspend/resume
>   function too
> 
>  drivers/mmc/host/sdhci-esdhc-imx.c |  2 +-
>  drivers/mmc/host/sdhci-pltfm.c     | 36 ++++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-pltfm.h     |  2 ++
>  3 files changed, 39 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index 82f512d..7b7b3a3 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -1132,7 +1132,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_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
>  	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
>  				sdhci_esdhc_runtime_resume, NULL)
>  };
> diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
> index a207f5a..38c03cd 100644
> --- a/drivers/mmc/host/sdhci-pltfm.c
> +++ b/drivers/mmc/host/sdhci-pltfm.c
> @@ -31,6 +31,7 @@
>  #include <linux/err.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/pm_runtime.h>
>  #ifdef CONFIG_PPC
>  #include <asm/machdep.h>
>  #endif
> @@ -256,6 +257,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
>  	.resume		= sdhci_pltfm_resume,
>  };
>  EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
> +
> +int sdhci_pltfm_rpm_suspend(struct device *dev)

Why invent a new API?
Can't put into sdhci_pltfm_suspend?

Regards
Dong Aisheng

> +{
> +	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);
> +	if (ret)
> +		return ret;
> +
> +	return pm_runtime_force_suspend(dev);
> +}
> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
> +
> +int sdhci_pltfm_rpm_resume(struct device *dev)
> +{
> +	int ret;
> +	struct sdhci_host *host = dev_get_drvdata(dev);
> +
> +	ret = pm_runtime_force_resume(dev);
> +
> +	if (ret)
> +		return ret;
> +
> +	pm_runtime_get_sync(dev);
> +	ret = sdhci_resume_host(host);
> +	pm_runtime_mark_last_busy(dev);
> +	pm_runtime_put_autosuspend(dev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
>  #endif	/* CONFIG_PM */
>  
>  static int __init sdhci_pltfm_drv_init(void)
> diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
> index 04bc248..ac5f6ea 100644
> --- a/drivers/mmc/host/sdhci-pltfm.h
> +++ b/drivers/mmc/host/sdhci-pltfm.h
> @@ -114,6 +114,8 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
>  extern int sdhci_pltfm_suspend(struct device *dev);
>  extern int sdhci_pltfm_resume(struct device *dev);
>  extern const struct dev_pm_ops sdhci_pltfm_pmops;
> +extern int sdhci_pltfm_rpm_suspend(struct device *dev);
> +extern int sdhci_pltfm_rpm_resume(struct device *dev);
>  #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
>  #else
>  #define SDHCI_PLTFM_PMOPS NULL
> -- 
> 2.4.1
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM
  2015-05-27 10:05   ` Dong Aisheng
@ 2015-05-27 10:40     ` Stefan Agner
  -1 siblings, 0 replies; 14+ messages in thread
From: Stefan Agner @ 2015-05-27 10:40 UTC (permalink / raw)
  To: Dong Aisheng
  Cc: ulf.hansson, gregory.clement, zhangfei.gao, jszhang, chris,
	anton, shawn.guo, linux-mmc, linux-arm-kernel, linux-kernel

On 2015-05-27 12:05, Dong Aisheng wrote:
<snip>
>> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
>> index 82f512d..7b7b3a3 100644
>> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
>> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
>> @@ -1132,7 +1132,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_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
>>  	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
>>  				sdhci_esdhc_runtime_resume, NULL)
>>  };
>> diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
>> index a207f5a..38c03cd 100644
>> --- a/drivers/mmc/host/sdhci-pltfm.c
>> +++ b/drivers/mmc/host/sdhci-pltfm.c
>> @@ -31,6 +31,7 @@
>>  #include <linux/err.h>
>>  #include <linux/module.h>
>>  #include <linux/of.h>
>> +#include <linux/pm_runtime.h>
>>  #ifdef CONFIG_PPC
>>  #include <asm/machdep.h>
>>  #endif
>> @@ -256,6 +257,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
>>  	.resume		= sdhci_pltfm_resume,
>>  };
>>  EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
>> +
>> +int sdhci_pltfm_rpm_suspend(struct device *dev)
> 
> Why invent a new API?
> Can't put into sdhci_pltfm_suspend?

There are several drivers making use of the API without runtime PM
support. Afaik, you can't call the pm_runtime functions without having
runtime PM support, at least pm_runtime_force_suspend seems to return an
error when runtime_suspend callback is not there... Maybe I'm wrong on
that?

--
Stefan

> 
> Regards
> Dong Aisheng
> 
>> +{
>> +	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);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return pm_runtime_force_suspend(dev);
>> +}
>> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
>> +
>> +int sdhci_pltfm_rpm_resume(struct device *dev)
>> +{
>> +	int ret;
>> +	struct sdhci_host *host = dev_get_drvdata(dev);
>> +
>> +	ret = pm_runtime_force_resume(dev);
>> +
>> +	if (ret)
>> +		return ret;
>> +
>> +	pm_runtime_get_sync(dev);
>> +	ret = sdhci_resume_host(host);
>> +	pm_runtime_mark_last_busy(dev);
>> +	pm_runtime_put_autosuspend(dev);
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
>>  #endif	/* CONFIG_PM */
>>
>>  static int __init sdhci_pltfm_drv_init(void)
>> diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
>> index 04bc248..ac5f6ea 100644
>> --- a/drivers/mmc/host/sdhci-pltfm.h
>> +++ b/drivers/mmc/host/sdhci-pltfm.h
>> @@ -114,6 +114,8 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
>>  extern int sdhci_pltfm_suspend(struct device *dev);
>>  extern int sdhci_pltfm_resume(struct device *dev);
>>  extern const struct dev_pm_ops sdhci_pltfm_pmops;
>> +extern int sdhci_pltfm_rpm_suspend(struct device *dev);
>> +extern int sdhci_pltfm_rpm_resume(struct device *dev);
>>  #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
>>  #else
>>  #define SDHCI_PLTFM_PMOPS NULL
>> --
>> 2.4.1
>>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM
@ 2015-05-27 10:40     ` Stefan Agner
  0 siblings, 0 replies; 14+ messages in thread
From: Stefan Agner @ 2015-05-27 10:40 UTC (permalink / raw)
  To: linux-arm-kernel

On 2015-05-27 12:05, Dong Aisheng wrote:
<snip>
>> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
>> index 82f512d..7b7b3a3 100644
>> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
>> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
>> @@ -1132,7 +1132,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_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
>>  	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
>>  				sdhci_esdhc_runtime_resume, NULL)
>>  };
>> diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
>> index a207f5a..38c03cd 100644
>> --- a/drivers/mmc/host/sdhci-pltfm.c
>> +++ b/drivers/mmc/host/sdhci-pltfm.c
>> @@ -31,6 +31,7 @@
>>  #include <linux/err.h>
>>  #include <linux/module.h>
>>  #include <linux/of.h>
>> +#include <linux/pm_runtime.h>
>>  #ifdef CONFIG_PPC
>>  #include <asm/machdep.h>
>>  #endif
>> @@ -256,6 +257,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
>>  	.resume		= sdhci_pltfm_resume,
>>  };
>>  EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
>> +
>> +int sdhci_pltfm_rpm_suspend(struct device *dev)
> 
> Why invent a new API?
> Can't put into sdhci_pltfm_suspend?

There are several drivers making use of the API without runtime PM
support. Afaik, you can't call the pm_runtime functions without having
runtime PM support, at least pm_runtime_force_suspend seems to return an
error when runtime_suspend callback is not there... Maybe I'm wrong on
that?

--
Stefan

> 
> Regards
> Dong Aisheng
> 
>> +{
>> +	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);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return pm_runtime_force_suspend(dev);
>> +}
>> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
>> +
>> +int sdhci_pltfm_rpm_resume(struct device *dev)
>> +{
>> +	int ret;
>> +	struct sdhci_host *host = dev_get_drvdata(dev);
>> +
>> +	ret = pm_runtime_force_resume(dev);
>> +
>> +	if (ret)
>> +		return ret;
>> +
>> +	pm_runtime_get_sync(dev);
>> +	ret = sdhci_resume_host(host);
>> +	pm_runtime_mark_last_busy(dev);
>> +	pm_runtime_put_autosuspend(dev);
>> +
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
>>  #endif	/* CONFIG_PM */
>>
>>  static int __init sdhci_pltfm_drv_init(void)
>> diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
>> index 04bc248..ac5f6ea 100644
>> --- a/drivers/mmc/host/sdhci-pltfm.h
>> +++ b/drivers/mmc/host/sdhci-pltfm.h
>> @@ -114,6 +114,8 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
>>  extern int sdhci_pltfm_suspend(struct device *dev);
>>  extern int sdhci_pltfm_resume(struct device *dev);
>>  extern const struct dev_pm_ops sdhci_pltfm_pmops;
>> +extern int sdhci_pltfm_rpm_suspend(struct device *dev);
>> +extern int sdhci_pltfm_rpm_resume(struct device *dev);
>>  #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
>>  #else
>>  #define SDHCI_PLTFM_PMOPS NULL
>> --
>> 2.4.1
>>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM
  2015-05-21  7:15 ` Stefan Agner
@ 2015-07-30 11:37   ` Stefan Agner
  -1 siblings, 0 replies; 14+ messages in thread
From: Stefan Agner @ 2015-07-30 11:37 UTC (permalink / raw)
  To: ulf.hansson
  Cc: gregory.clement, zhangfei.gao, jszhang, chris, anton, b29396,
	shawn.guo, linux-mmc, linux-arm-kernel, linux-kernel

Hi Ulf,

What is the status on that?

--
Stefan

On 2015-05-21 09:15, Stefan Agner wrote:
> When using i.MX ESDHC driver, while 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 runtime PM enabled pltfm implementation of suspend/resume which
> take care of clocks by using the runtime PM API properly.
> 
> Signed-off-by: Stefan Agner <stefan@agner.ch>
> ---
> Changes since v2:
> - Implement a generic pltfm suspend/resume function instead of a local
>   function in sdhci-esdhc-imx.c
> - Convert sdhci-pxav3 to use the runtime PM enabled pltfm suspend/resume
>   function too
> 
>  drivers/mmc/host/sdhci-esdhc-imx.c |  2 +-
>  drivers/mmc/host/sdhci-pltfm.c     | 36 ++++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-pltfm.h     |  2 ++
>  3 files changed, 39 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
> b/drivers/mmc/host/sdhci-esdhc-imx.c
> index 82f512d..7b7b3a3 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -1132,7 +1132,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_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
>  	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
>  				sdhci_esdhc_runtime_resume, NULL)
>  };
> diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
> index a207f5a..38c03cd 100644
> --- a/drivers/mmc/host/sdhci-pltfm.c
> +++ b/drivers/mmc/host/sdhci-pltfm.c
> @@ -31,6 +31,7 @@
>  #include <linux/err.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/pm_runtime.h>
>  #ifdef CONFIG_PPC
>  #include <asm/machdep.h>
>  #endif
> @@ -256,6 +257,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
>  	.resume		= sdhci_pltfm_resume,
>  };
>  EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
> +
> +int sdhci_pltfm_rpm_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);
> +	if (ret)
> +		return ret;
> +
> +	return pm_runtime_force_suspend(dev);
> +}
> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
> +
> +int sdhci_pltfm_rpm_resume(struct device *dev)
> +{
> +	int ret;
> +	struct sdhci_host *host = dev_get_drvdata(dev);
> +
> +	ret = pm_runtime_force_resume(dev);
> +
> +	if (ret)
> +		return ret;
> +
> +	pm_runtime_get_sync(dev);
> +	ret = sdhci_resume_host(host);
> +	pm_runtime_mark_last_busy(dev);
> +	pm_runtime_put_autosuspend(dev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
>  #endif	/* CONFIG_PM */
>  
>  static int __init sdhci_pltfm_drv_init(void)
> diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
> index 04bc248..ac5f6ea 100644
> --- a/drivers/mmc/host/sdhci-pltfm.h
> +++ b/drivers/mmc/host/sdhci-pltfm.h
> @@ -114,6 +114,8 @@ static inline void *sdhci_pltfm_priv(struct
> sdhci_pltfm_host *host)
>  extern int sdhci_pltfm_suspend(struct device *dev);
>  extern int sdhci_pltfm_resume(struct device *dev);
>  extern const struct dev_pm_ops sdhci_pltfm_pmops;
> +extern int sdhci_pltfm_rpm_suspend(struct device *dev);
> +extern int sdhci_pltfm_rpm_resume(struct device *dev);
>  #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
>  #else
>  #define SDHCI_PLTFM_PMOPS NULL


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM
@ 2015-07-30 11:37   ` Stefan Agner
  0 siblings, 0 replies; 14+ messages in thread
From: Stefan Agner @ 2015-07-30 11:37 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ulf,

What is the status on that?

--
Stefan

On 2015-05-21 09:15, Stefan Agner wrote:
> When using i.MX ESDHC driver, while 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 runtime PM enabled pltfm implementation of suspend/resume which
> take care of clocks by using the runtime PM API properly.
> 
> Signed-off-by: Stefan Agner <stefan@agner.ch>
> ---
> Changes since v2:
> - Implement a generic pltfm suspend/resume function instead of a local
>   function in sdhci-esdhc-imx.c
> - Convert sdhci-pxav3 to use the runtime PM enabled pltfm suspend/resume
>   function too
> 
>  drivers/mmc/host/sdhci-esdhc-imx.c |  2 +-
>  drivers/mmc/host/sdhci-pltfm.c     | 36 ++++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci-pltfm.h     |  2 ++
>  3 files changed, 39 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
> b/drivers/mmc/host/sdhci-esdhc-imx.c
> index 82f512d..7b7b3a3 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -1132,7 +1132,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_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
>  	SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
>  				sdhci_esdhc_runtime_resume, NULL)
>  };
> diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
> index a207f5a..38c03cd 100644
> --- a/drivers/mmc/host/sdhci-pltfm.c
> +++ b/drivers/mmc/host/sdhci-pltfm.c
> @@ -31,6 +31,7 @@
>  #include <linux/err.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/pm_runtime.h>
>  #ifdef CONFIG_PPC
>  #include <asm/machdep.h>
>  #endif
> @@ -256,6 +257,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
>  	.resume		= sdhci_pltfm_resume,
>  };
>  EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
> +
> +int sdhci_pltfm_rpm_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);
> +	if (ret)
> +		return ret;
> +
> +	return pm_runtime_force_suspend(dev);
> +}
> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
> +
> +int sdhci_pltfm_rpm_resume(struct device *dev)
> +{
> +	int ret;
> +	struct sdhci_host *host = dev_get_drvdata(dev);
> +
> +	ret = pm_runtime_force_resume(dev);
> +
> +	if (ret)
> +		return ret;
> +
> +	pm_runtime_get_sync(dev);
> +	ret = sdhci_resume_host(host);
> +	pm_runtime_mark_last_busy(dev);
> +	pm_runtime_put_autosuspend(dev);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
>  #endif	/* CONFIG_PM */
>  
>  static int __init sdhci_pltfm_drv_init(void)
> diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
> index 04bc248..ac5f6ea 100644
> --- a/drivers/mmc/host/sdhci-pltfm.h
> +++ b/drivers/mmc/host/sdhci-pltfm.h
> @@ -114,6 +114,8 @@ static inline void *sdhci_pltfm_priv(struct
> sdhci_pltfm_host *host)
>  extern int sdhci_pltfm_suspend(struct device *dev);
>  extern int sdhci_pltfm_resume(struct device *dev);
>  extern const struct dev_pm_ops sdhci_pltfm_pmops;
> +extern int sdhci_pltfm_rpm_suspend(struct device *dev);
> +extern int sdhci_pltfm_rpm_resume(struct device *dev);
>  #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
>  #else
>  #define SDHCI_PLTFM_PMOPS NULL

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM
  2015-07-30 11:37   ` Stefan Agner
  (?)
@ 2015-08-25 12:04     ` Ulf Hansson
  -1 siblings, 0 replies; 14+ messages in thread
From: Ulf Hansson @ 2015-08-25 12:04 UTC (permalink / raw)
  To: Stefan Agner
  Cc: Gregory Clement, zhangfei.gao, Jisheng Zhang, Chris Ball,
	Anton Vorontsov, Dong Aisheng, Shawn Guo, linux-mmc,
	linux-arm-kernel, linux-kernel

On 30 July 2015 at 13:37, Stefan Agner <stefan@agner.ch> wrote:
> Hi Ulf,
>
> What is the status on that?
>
> --
> Stefan
>
> On 2015-05-21 09:15, Stefan Agner wrote:
>> When using i.MX ESDHC driver, while 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 runtime PM enabled pltfm implementation of suspend/resume which
>> take care of clocks by using the runtime PM API properly.
>>
>> Signed-off-by: Stefan Agner <stefan@agner.ch>
>> ---
>> Changes since v2:
>> - Implement a generic pltfm suspend/resume function instead of a local
>>   function in sdhci-esdhc-imx.c
>> - Convert sdhci-pxav3 to use the runtime PM enabled pltfm suspend/resume
>>   function too
>>
>>  drivers/mmc/host/sdhci-esdhc-imx.c |  2 +-
>>  drivers/mmc/host/sdhci-pltfm.c     | 36 ++++++++++++++++++++++++++++++++++++
>>  drivers/mmc/host/sdhci-pltfm.h     |  2 ++
>>  3 files changed, 39 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
>> b/drivers/mmc/host/sdhci-esdhc-imx.c
>> index 82f512d..7b7b3a3 100644
>> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
>> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
>> @@ -1132,7 +1132,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_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
>>       SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
>>                               sdhci_esdhc_runtime_resume, NULL)
>>  };
>> diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
>> index a207f5a..38c03cd 100644
>> --- a/drivers/mmc/host/sdhci-pltfm.c
>> +++ b/drivers/mmc/host/sdhci-pltfm.c
>> @@ -31,6 +31,7 @@
>>  #include <linux/err.h>
>>  #include <linux/module.h>
>>  #include <linux/of.h>
>> +#include <linux/pm_runtime.h>
>>  #ifdef CONFIG_PPC
>>  #include <asm/machdep.h>
>>  #endif
>> @@ -256,6 +257,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
>>       .resume         = sdhci_pltfm_resume,
>>  };
>>  EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
>> +
>> +int sdhci_pltfm_rpm_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);
>> +     if (ret)
>> +             return ret;
>> +
>> +     return pm_runtime_force_suspend(dev);
>> +}
>> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
>> +
>> +int sdhci_pltfm_rpm_resume(struct device *dev)
>> +{
>> +     int ret;
>> +     struct sdhci_host *host = dev_get_drvdata(dev);
>> +
>> +     ret = pm_runtime_force_resume(dev);
>> +
>> +     if (ret)
>> +             return ret;
>> +
>> +     pm_runtime_get_sync(dev);
>> +     ret = sdhci_resume_host(host);
>> +     pm_runtime_mark_last_busy(dev);
>> +     pm_runtime_put_autosuspend(dev);
>> +
>> +     return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
>>  #endif       /* CONFIG_PM */
>>
>>  static int __init sdhci_pltfm_drv_init(void)
>> diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
>> index 04bc248..ac5f6ea 100644
>> --- a/drivers/mmc/host/sdhci-pltfm.h
>> +++ b/drivers/mmc/host/sdhci-pltfm.h
>> @@ -114,6 +114,8 @@ static inline void *sdhci_pltfm_priv(struct
>> sdhci_pltfm_host *host)
>>  extern int sdhci_pltfm_suspend(struct device *dev);
>>  extern int sdhci_pltfm_resume(struct device *dev);
>>  extern const struct dev_pm_ops sdhci_pltfm_pmops;
>> +extern int sdhci_pltfm_rpm_suspend(struct device *dev);
>> +extern int sdhci_pltfm_rpm_resume(struct device *dev);
>>  #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
>>  #else
>>  #define SDHCI_PLTFM_PMOPS NULL
>

This is a bit complicated, mostly due to the code structure of sdhci
and around how it handles wakeup settings. I do understand that you
want to fix a real bug, but in this case I think we need to figure out
a long term solution, else we will be solving one problem but
inserting another.

Obviously the sdhci device needs to be runtime resumed while accessing
it. Now, I wonder *why* sdhci-pltfm drivers need to access their
devices during system suspend? Normally that's because you want to
apply a different wakeup configuration in system suspend than in
runtime suspend, but is that really the case? And if so, could we
teach sdhci_runtime_suspend_host() to deal with this?

So, I think we first need to understand how to let sdhci deal with
wakeups. By cleaning up that piece of code and possibly also
converting it to use the new wakeirq API
(drivers/base/power/wakeirq.c) we should be better prepared to apply a
proper fix for your issue.

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM
@ 2015-08-25 12:04     ` Ulf Hansson
  0 siblings, 0 replies; 14+ messages in thread
From: Ulf Hansson @ 2015-08-25 12:04 UTC (permalink / raw)
  To: Stefan Agner
  Cc: Gregory Clement, zhangfei.gao, Jisheng Zhang, Chris Ball,
	Anton Vorontsov, Dong Aisheng, Shawn Guo, linux-mmc,
	linux-arm-kernel, linux-kernel

On 30 July 2015 at 13:37, Stefan Agner <stefan@agner.ch> wrote:
> Hi Ulf,
>
> What is the status on that?
>
> --
> Stefan
>
> On 2015-05-21 09:15, Stefan Agner wrote:
>> When using i.MX ESDHC driver, while 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 runtime PM enabled pltfm implementation of suspend/resume which
>> take care of clocks by using the runtime PM API properly.
>>
>> Signed-off-by: Stefan Agner <stefan@agner.ch>
>> ---
>> Changes since v2:
>> - Implement a generic pltfm suspend/resume function instead of a local
>>   function in sdhci-esdhc-imx.c
>> - Convert sdhci-pxav3 to use the runtime PM enabled pltfm suspend/resume
>>   function too
>>
>>  drivers/mmc/host/sdhci-esdhc-imx.c |  2 +-
>>  drivers/mmc/host/sdhci-pltfm.c     | 36 ++++++++++++++++++++++++++++++++++++
>>  drivers/mmc/host/sdhci-pltfm.h     |  2 ++
>>  3 files changed, 39 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
>> b/drivers/mmc/host/sdhci-esdhc-imx.c
>> index 82f512d..7b7b3a3 100644
>> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
>> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
>> @@ -1132,7 +1132,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_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
>>       SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
>>                               sdhci_esdhc_runtime_resume, NULL)
>>  };
>> diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
>> index a207f5a..38c03cd 100644
>> --- a/drivers/mmc/host/sdhci-pltfm.c
>> +++ b/drivers/mmc/host/sdhci-pltfm.c
>> @@ -31,6 +31,7 @@
>>  #include <linux/err.h>
>>  #include <linux/module.h>
>>  #include <linux/of.h>
>> +#include <linux/pm_runtime.h>
>>  #ifdef CONFIG_PPC
>>  #include <asm/machdep.h>
>>  #endif
>> @@ -256,6 +257,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
>>       .resume         = sdhci_pltfm_resume,
>>  };
>>  EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
>> +
>> +int sdhci_pltfm_rpm_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);
>> +     if (ret)
>> +             return ret;
>> +
>> +     return pm_runtime_force_suspend(dev);
>> +}
>> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
>> +
>> +int sdhci_pltfm_rpm_resume(struct device *dev)
>> +{
>> +     int ret;
>> +     struct sdhci_host *host = dev_get_drvdata(dev);
>> +
>> +     ret = pm_runtime_force_resume(dev);
>> +
>> +     if (ret)
>> +             return ret;
>> +
>> +     pm_runtime_get_sync(dev);
>> +     ret = sdhci_resume_host(host);
>> +     pm_runtime_mark_last_busy(dev);
>> +     pm_runtime_put_autosuspend(dev);
>> +
>> +     return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
>>  #endif       /* CONFIG_PM */
>>
>>  static int __init sdhci_pltfm_drv_init(void)
>> diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
>> index 04bc248..ac5f6ea 100644
>> --- a/drivers/mmc/host/sdhci-pltfm.h
>> +++ b/drivers/mmc/host/sdhci-pltfm.h
>> @@ -114,6 +114,8 @@ static inline void *sdhci_pltfm_priv(struct
>> sdhci_pltfm_host *host)
>>  extern int sdhci_pltfm_suspend(struct device *dev);
>>  extern int sdhci_pltfm_resume(struct device *dev);
>>  extern const struct dev_pm_ops sdhci_pltfm_pmops;
>> +extern int sdhci_pltfm_rpm_suspend(struct device *dev);
>> +extern int sdhci_pltfm_rpm_resume(struct device *dev);
>>  #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
>>  #else
>>  #define SDHCI_PLTFM_PMOPS NULL
>

This is a bit complicated, mostly due to the code structure of sdhci
and around how it handles wakeup settings. I do understand that you
want to fix a real bug, but in this case I think we need to figure out
a long term solution, else we will be solving one problem but
inserting another.

Obviously the sdhci device needs to be runtime resumed while accessing
it. Now, I wonder *why* sdhci-pltfm drivers need to access their
devices during system suspend? Normally that's because you want to
apply a different wakeup configuration in system suspend than in
runtime suspend, but is that really the case? And if so, could we
teach sdhci_runtime_suspend_host() to deal with this?

So, I think we first need to understand how to let sdhci deal with
wakeups. By cleaning up that piece of code and possibly also
converting it to use the new wakeirq API
(drivers/base/power/wakeirq.c) we should be better prepared to apply a
proper fix for your issue.

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM
@ 2015-08-25 12:04     ` Ulf Hansson
  0 siblings, 0 replies; 14+ messages in thread
From: Ulf Hansson @ 2015-08-25 12:04 UTC (permalink / raw)
  To: linux-arm-kernel

On 30 July 2015 at 13:37, Stefan Agner <stefan@agner.ch> wrote:
> Hi Ulf,
>
> What is the status on that?
>
> --
> Stefan
>
> On 2015-05-21 09:15, Stefan Agner wrote:
>> When using i.MX ESDHC driver, while 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 runtime PM enabled pltfm implementation of suspend/resume which
>> take care of clocks by using the runtime PM API properly.
>>
>> Signed-off-by: Stefan Agner <stefan@agner.ch>
>> ---
>> Changes since v2:
>> - Implement a generic pltfm suspend/resume function instead of a local
>>   function in sdhci-esdhc-imx.c
>> - Convert sdhci-pxav3 to use the runtime PM enabled pltfm suspend/resume
>>   function too
>>
>>  drivers/mmc/host/sdhci-esdhc-imx.c |  2 +-
>>  drivers/mmc/host/sdhci-pltfm.c     | 36 ++++++++++++++++++++++++++++++++++++
>>  drivers/mmc/host/sdhci-pltfm.h     |  2 ++
>>  3 files changed, 39 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
>> b/drivers/mmc/host/sdhci-esdhc-imx.c
>> index 82f512d..7b7b3a3 100644
>> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
>> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
>> @@ -1132,7 +1132,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_pltfm_rpm_suspend, sdhci_pltfm_rpm_resume)
>>       SET_RUNTIME_PM_OPS(sdhci_esdhc_runtime_suspend,
>>                               sdhci_esdhc_runtime_resume, NULL)
>>  };
>> diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
>> index a207f5a..38c03cd 100644
>> --- a/drivers/mmc/host/sdhci-pltfm.c
>> +++ b/drivers/mmc/host/sdhci-pltfm.c
>> @@ -31,6 +31,7 @@
>>  #include <linux/err.h>
>>  #include <linux/module.h>
>>  #include <linux/of.h>
>> +#include <linux/pm_runtime.h>
>>  #ifdef CONFIG_PPC
>>  #include <asm/machdep.h>
>>  #endif
>> @@ -256,6 +257,41 @@ const struct dev_pm_ops sdhci_pltfm_pmops = {
>>       .resume         = sdhci_pltfm_resume,
>>  };
>>  EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
>> +
>> +int sdhci_pltfm_rpm_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);
>> +     if (ret)
>> +             return ret;
>> +
>> +     return pm_runtime_force_suspend(dev);
>> +}
>> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_suspend);
>> +
>> +int sdhci_pltfm_rpm_resume(struct device *dev)
>> +{
>> +     int ret;
>> +     struct sdhci_host *host = dev_get_drvdata(dev);
>> +
>> +     ret = pm_runtime_force_resume(dev);
>> +
>> +     if (ret)
>> +             return ret;
>> +
>> +     pm_runtime_get_sync(dev);
>> +     ret = sdhci_resume_host(host);
>> +     pm_runtime_mark_last_busy(dev);
>> +     pm_runtime_put_autosuspend(dev);
>> +
>> +     return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(sdhci_pltfm_rpm_resume);
>>  #endif       /* CONFIG_PM */
>>
>>  static int __init sdhci_pltfm_drv_init(void)
>> diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
>> index 04bc248..ac5f6ea 100644
>> --- a/drivers/mmc/host/sdhci-pltfm.h
>> +++ b/drivers/mmc/host/sdhci-pltfm.h
>> @@ -114,6 +114,8 @@ static inline void *sdhci_pltfm_priv(struct
>> sdhci_pltfm_host *host)
>>  extern int sdhci_pltfm_suspend(struct device *dev);
>>  extern int sdhci_pltfm_resume(struct device *dev);
>>  extern const struct dev_pm_ops sdhci_pltfm_pmops;
>> +extern int sdhci_pltfm_rpm_suspend(struct device *dev);
>> +extern int sdhci_pltfm_rpm_resume(struct device *dev);
>>  #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
>>  #else
>>  #define SDHCI_PLTFM_PMOPS NULL
>

This is a bit complicated, mostly due to the code structure of sdhci
and around how it handles wakeup settings. I do understand that you
want to fix a real bug, but in this case I think we need to figure out
a long term solution, else we will be solving one problem but
inserting another.

Obviously the sdhci device needs to be runtime resumed while accessing
it. Now, I wonder *why* sdhci-pltfm drivers need to access their
devices during system suspend? Normally that's because you want to
apply a different wakeup configuration in system suspend than in
runtime suspend, but is that really the case? And if so, could we
teach sdhci_runtime_suspend_host() to deal with this?

So, I think we first need to understand how to let sdhci deal with
wakeups. By cleaning up that piece of code and possibly also
converting it to use the new wakeirq API
(drivers/base/power/wakeirq.c) we should be better prepared to apply a
proper fix for your issue.

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2015-08-25 12:04 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-21  7:15 [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM Stefan Agner
2015-05-21  7:15 ` Stefan Agner
2015-05-21  7:15 ` [PATCH v3 2/2] mmc: sdhci-pxav3: use runtime_pm enabled pltfm suspend/resume Stefan Agner
2015-05-21  7:15   ` Stefan Agner
2015-05-27 10:05 ` [PATCH v3 1/2] mmc: sdhci: fix abort due to missing runtime PM Dong Aisheng
2015-05-27 10:05   ` Dong Aisheng
2015-05-27 10:05   ` Dong Aisheng
2015-05-27 10:40   ` Stefan Agner
2015-05-27 10:40     ` Stefan Agner
2015-07-30 11:37 ` Stefan Agner
2015-07-30 11:37   ` Stefan Agner
2015-08-25 12:04   ` Ulf Hansson
2015-08-25 12:04     ` Ulf Hansson
2015-08-25 12:04     ` Ulf Hansson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.