mmc: core: postpone runtime suspend in case BKOPS is required
Some devices require long BKOPs time in order to provide high performance. In the current solution, the host disables auto BKOPs or stops manual BKOPs in runtime suspend, regardless of the device need for BKOPs. This patch adds a check for device BKOPs status and defers suspend in case when BKOPs need. CRs-Fixed: 979630 Change-Id: Ib38d1ce58e4195d4969e9a367b5738c8e598d0ba Signed-off-by: Konstantin Dorfman <kdorfman@codeaurora.org> [subhashj@codeaurora.org: fixed merge conflicts] Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
parent
127468f482
commit
5c8d743546
4 changed files with 76 additions and 11 deletions
|
@ -1227,6 +1227,8 @@ int mmc_set_auto_bkops(struct mmc_card *card, bool enable)
|
|||
mmc_update_bkops_auto_off(&card->bkops.stats);
|
||||
}
|
||||
card->ext_csd.man_bkops_en = bkops_en;
|
||||
pr_debug("%s: %s: bkops state %x\n",
|
||||
mmc_hostname(card->host), __func__, bkops_en);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
|
@ -1246,9 +1248,7 @@ void mmc_check_bkops(struct mmc_card *card)
|
|||
|
||||
BUG_ON(!card);
|
||||
|
||||
if (unlikely(!mmc_card_configured_manual_bkops(card)))
|
||||
return;
|
||||
if (mmc_card_doing_bkops(card) || mmc_card_doing_auto_bkops(card))
|
||||
if (mmc_card_doing_bkops(card))
|
||||
return;
|
||||
|
||||
err = mmc_read_bkops_status(card);
|
||||
|
@ -1258,12 +1258,12 @@ void mmc_check_bkops(struct mmc_card *card)
|
|||
return;
|
||||
}
|
||||
|
||||
card->bkops.needs_check = false;
|
||||
|
||||
mmc_update_bkops_level(&card->bkops.stats,
|
||||
card->ext_csd.raw_bkops_status);
|
||||
if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2)
|
||||
return;
|
||||
|
||||
card->bkops.needs_manual = true;
|
||||
card->bkops.needs_bkops = card->ext_csd.raw_bkops_status > 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_check_bkops);
|
||||
|
||||
|
@ -1296,7 +1296,7 @@ void mmc_start_manual_bkops(struct mmc_card *card)
|
|||
} else {
|
||||
mmc_card_set_doing_bkops(card);
|
||||
mmc_update_bkops_start(&card->bkops.stats);
|
||||
card->bkops.needs_manual = false;
|
||||
card->bkops.needs_bkops = false;
|
||||
}
|
||||
|
||||
mmc_retune_release(card->host);
|
||||
|
|
|
@ -2713,6 +2713,64 @@ static int mmc_resume(struct mmc_host *host)
|
|||
return err;
|
||||
}
|
||||
|
||||
#define MAX_DEFER_SUSPEND_COUNTER 20
|
||||
static bool mmc_process_bkops(struct mmc_host *host)
|
||||
{
|
||||
int err = 0;
|
||||
bool is_running = false;
|
||||
u32 status;
|
||||
|
||||
mmc_claim_host(host);
|
||||
if (mmc_card_cmdq(host->card)) {
|
||||
BUG_ON(host->cmdq_ctx.active_reqs);
|
||||
|
||||
err = mmc_cmdq_halt(host, true);
|
||||
if (err) {
|
||||
pr_err("%s: halt: failed: %d\n", __func__, err);
|
||||
goto unhalt;
|
||||
}
|
||||
}
|
||||
|
||||
if (mmc_card_doing_bkops(host->card)) {
|
||||
/* check that manual bkops finished */
|
||||
err = mmc_send_status(host->card, &status);
|
||||
if (err) {
|
||||
pr_err("%s: Get card status fail\n", __func__);
|
||||
goto unhalt;
|
||||
}
|
||||
if (R1_CURRENT_STATE(status) != R1_STATE_PRG) {
|
||||
mmc_card_clr_doing_bkops(host->card);
|
||||
goto unhalt;
|
||||
}
|
||||
} else {
|
||||
mmc_check_bkops(host->card);
|
||||
}
|
||||
|
||||
if (host->card->bkops.needs_bkops &&
|
||||
!mmc_card_support_auto_bkops(host->card))
|
||||
mmc_start_manual_bkops(host->card);
|
||||
|
||||
unhalt:
|
||||
if (mmc_card_cmdq(host->card)) {
|
||||
err = mmc_cmdq_halt(host, false);
|
||||
if (err)
|
||||
pr_err("%s: unhalt: failed: %d\n", __func__, err);
|
||||
}
|
||||
mmc_release_host(host);
|
||||
|
||||
if (host->card->bkops.needs_bkops ||
|
||||
mmc_card_doing_bkops(host->card)) {
|
||||
if (host->card->bkops.retry_counter++ <
|
||||
MAX_DEFER_SUSPEND_COUNTER) {
|
||||
host->card->bkops.needs_check = true;
|
||||
is_running = true;
|
||||
} else {
|
||||
host->card->bkops.retry_counter = 0;
|
||||
}
|
||||
}
|
||||
return is_running;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for runtime_suspend.
|
||||
*/
|
||||
|
@ -2724,6 +2782,12 @@ static int mmc_runtime_suspend(struct mmc_host *host)
|
|||
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
|
||||
return 0;
|
||||
|
||||
if (mmc_process_bkops(host)) {
|
||||
pm_runtime_mark_last_busy(&host->card->dev);
|
||||
pr_debug("%s: defered, need bkops\n", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
err = _mmc_suspend(host, true);
|
||||
if (err)
|
||||
pr_err("%s: error %d doing aggressive suspend\n",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -876,8 +876,8 @@ skip_cqterri:
|
|||
* exception once the queue is empty
|
||||
*/
|
||||
BUG_ON(!mmc->card);
|
||||
if (mmc_card_configured_manual_bkops(mmc->card) &&
|
||||
!mmc_card_configured_auto_bkops(mmc->card))
|
||||
if (mmc_card_configured_manual_bkops(mmc->card) ||
|
||||
mmc_card_configured_auto_bkops(mmc->card))
|
||||
mmc->card->bkops.needs_check = true;
|
||||
|
||||
mrq->cmdq_req->resp_err = true;
|
||||
|
|
|
@ -327,7 +327,8 @@ struct mmc_bkops_stats {
|
|||
struct mmc_bkops_info {
|
||||
struct mmc_bkops_stats stats;
|
||||
bool needs_check;
|
||||
bool needs_manual;
|
||||
bool needs_bkops;
|
||||
u32 retry_counter;
|
||||
};
|
||||
|
||||
enum mmc_pon_type {
|
||||
|
|
Loading…
Add table
Reference in a new issue