Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3fe7b483 authored by Konstantin Dorfman's avatar Konstantin Dorfman
Browse files

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: default avatarKonstantin Dorfman <kdorfman@codeaurora.org>
parent a8371783
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -1170,6 +1170,8 @@ int mmc_set_auto_bkops(struct mmc_card *card, bool enable)
			mmc_update_bkops_auto_off(&card->bkops.stats);
		}
		card->ext_csd.bkops_en = bkops_en;
		pr_debug("%s: %s: bkops state %x\n",
				mmc_hostname(card->host), __func__, bkops_en);
	}
out:
	return ret;
@@ -1189,9 +1191,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);
@@ -1201,12 +1201,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);

@@ -1237,7 +1237,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;
	}
}
EXPORT_SYMBOL(mmc_start_manual_bkops);
+64 −0
Original line number Diff line number Diff line
@@ -2576,6 +2576,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.
 */
@@ -2587,6 +2645,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 aggessive suspend\n",
+3 −3
Original line number Diff line number Diff line
/* 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;
+2 −1
Original line number Diff line number Diff line
@@ -324,7 +324,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 {