From 7246b950418ccf085b9af676066b46a291708eff Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Sun, 4 Dec 2016 21:37:41 +0530 Subject: [PATCH] mmc: mmc: Handle error case in mmc_suspend Currently in case if suspend is failed due to some reason then the error case is not handled properly :- 1. w.r.t. suspend_clk_scaling claim_host counters are going bad. 2. In case of any error after halting and disabling cmdq - the error is returned to the PM framework and it assumes that card is not suspended, whereas CQ remains disabled. This causes I/O requests hangs since no request can be processed any further. Fix this by handling error cases properly. Change-Id: I8691eebcb0e2d089720505475aa0297efce5cca5 Signed-off-by: Ritesh Harjani Signed-off-by: Sayali Lokhande Signed-off-by: Siba Prasad --- drivers/mmc/core/mmc.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 414877874190..4567b7526469 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -2494,7 +2494,7 @@ static int mmc_test_awake_ext_csd(struct mmc_host *host) static int _mmc_suspend(struct mmc_host *host, bool is_suspend) { - int err = 0; + int err = 0, ret; BUG_ON(!host); BUG_ON(!host->card); @@ -2503,6 +2503,8 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) if (err) { pr_err("%s: %s: fail to suspend clock scaling (%d)\n", mmc_hostname(host), __func__, err); + if (host->card->cmdq_init) + wake_up(&host->cmdq_ctx.wait); return err; } @@ -2527,12 +2529,12 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) if (mmc_card_doing_bkops(host->card)) { err = mmc_stop_bkops(host->card); if (err) - goto out; + goto out_err; } err = mmc_flush_cache(host->card); if (err) - goto out; + goto out_err; if (mmc_can_sleepawake(host)) { /* @@ -2549,16 +2551,38 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) err = mmc_deselect_cards(host); } - if (!err) { - mmc_power_off(host); - mmc_card_set_suspended(host->card); + if (err) + goto out_err; + mmc_power_off(host); + mmc_card_set_suspended(host->card); + + goto out; + +out_err: + /* + * In case of err let's put controller back in cmdq mode and unhalt + * the controller. + * We expect cmdq_enable and unhalt won't return any error + * since it is anyway enabling few registers. + */ + if (host->card->cmdq_init) { + mmc_host_clk_hold(host); + ret = host->cmdq_ops->enable(host); + if (ret) + pr_err("%s: %s: enabling CMDQ mode failed (%d)\n", + mmc_hostname(host), __func__, ret); + mmc_host_clk_release(host); + mmc_cmdq_halt(host, false); } + out: /* Kick CMDQ thread to process any requests came in while suspending */ if (host->card->cmdq_init) wake_up(&host->cmdq_ctx.wait); mmc_release_host(host); + if (err) + mmc_resume_clk_scaling(host); return err; }