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:
Konstantin Dorfman 2015-12-31 14:45:48 +02:00 committed by Subhash Jadavani
parent 127468f482
commit 5c8d743546
4 changed files with 76 additions and 11 deletions

View file

@ -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);

View file

@ -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",

View file

@ -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;

View file

@ -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 {