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

Commit 00fe7583 authored by Talel Shenhar's avatar Talel Shenhar
Browse files

mmc: core: add support for devfreq suspend/resume



This change adds use of devfreq suspend/resume API.
In the current version of the code, devfreq is fully brought
up/down on each runtime resume/suspend which causes
statistics loss and is time consuming.
This change addresses the above by adding support for
devfreq suspend/resume to be called on each system
suspend/resume, runtime suspend/resume, power restore.

Change-Id: Id209826fb9499084ae96c7d3a47e4032326f61e9
Signed-off-by: default avatarTalel Shenhar <tatias@codeaurora.org>
parent 2d0f0840
Loading
Loading
Loading
Loading
+96 −52
Original line number Diff line number Diff line
@@ -258,25 +258,6 @@ out:
}
EXPORT_SYMBOL(mmc_cmdq_clk_scaling_stop_busy);

/**
 * mmc_disable_devfreq_clk_scaling() - Disable clock scaling
 * @host: pointer to mmc host structure
 *
 * Disables clock scaling aggresively
 */
void mmc_disable_clk_scaling(struct mmc_host *host)
{
	if (!host) {
		pr_err("bad host parameter\n");
		WARN_ON(1);
		return;
	}
	pr_debug("%s: disabling clock scaling\n", mmc_hostname(host));
	mmc_exit_clk_scaling(host);

}
EXPORT_SYMBOL(mmc_disable_clk_scaling);

/**
 * mmc_can_scale_clk() - Check clock scaling capability
 * @host: pointer to mmc host structure
@@ -289,8 +270,7 @@ bool mmc_can_scale_clk(struct mmc_host *host)
		return false;
	}

	return (host->caps2 & MMC_CAP2_CLK_SCALE) &&
		(!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY));
	return host->caps2 & MMC_CAP2_CLK_SCALE;
}
EXPORT_SYMBOL(mmc_can_scale_clk);

@@ -738,18 +718,20 @@ int mmc_init_clk_scaling(struct mmc_host *host)
EXPORT_SYMBOL(mmc_init_clk_scaling);

/**
 * mmc_exit_devfreq_clk_scaling() - Disable clock scaling
 * mmc_suspend_clk_scaling() - suspend clock scaling
 * @host: pointer to mmc host structure
 *
 * Disable clock scaling permanently.
 * This API will suspend devfreq feature for the specific host.
 * The statistics collected by mmc will be cleared.
 * This function is intended to be called by the pm callbacks
 * (e.g. runtime_suspend, suspend) of the mmc device
 */
int mmc_exit_clk_scaling(struct mmc_host *host)
int mmc_suspend_clk_scaling(struct mmc_host *host)
{
	int err;

	if (!host) {
		pr_err("bad host parameter\n");
		WARN_ON(1);
		WARN(1, "bad host parameter\n");
		return -EINVAL;
	}

@@ -757,55 +739,118 @@ int mmc_exit_clk_scaling(struct mmc_host *host)
		return 0;

	if (!host->clk_scaling.devfreq) {
		pr_err("%s: no devfreq is assosiated with this device\n",
			mmc_hostname(host));
		pr_err("%s: %s: no devfreq is assosiated with this device\n",
			mmc_hostname(host), __func__);
		return -EPERM;
	}

	host->clk_scaling.enable = false;
	atomic_inc(&host->clk_scaling.devfreq_abort);
	err = devfreq_suspend_device(host->clk_scaling.devfreq);
	if (err) {
		pr_err("%s: failed to suspend devfreq\n", mmc_hostname(host));
		pr_err("%s: %s: failed to suspend devfreq\n",
			mmc_hostname(host), __func__);
		return err;
	}
	host->clk_scaling.enable = false;

	host->clk_scaling.total_busy_time_us = 0;

	pr_debug("%s: devfreq suspended\n", mmc_hostname(host));

	err = devfreq_remove_device(host->clk_scaling.devfreq);
	if (err) {
		pr_err("%s: remove devfreq failed\n", mmc_hostname(host));
		return err;
	return 0;
}
EXPORT_SYMBOL(mmc_suspend_clk_scaling);

	host->clk_scaling.devfreq = NULL;
	atomic_set(&host->clk_scaling.devfreq_abort, 1);
	mmc_reset_clk_scale_stats(host);
	pr_debug("%s: devfreq was removed\n", mmc_hostname(host));
/**
 * mmc_resume_clk_scaling() - resume clock scaling
 * @host: pointer to mmc host structure
 *
 * This API will resume devfreq feature for the specific host.
 * This API is intended to be called by the pm callbacks
 * (e.g. runtime_suspend, suspend) of the mmc device
 */
int mmc_resume_clk_scaling(struct mmc_host *host)
{
	int err = 0;

	if (!host) {
		WARN(1, "bad host parameter\n");
		return -EINVAL;
	}

	if (!mmc_can_scale_clk(host))
		return 0;

	if (!host->clk_scaling.devfreq) {
		pr_err("%s: %s: no devfreq is assosiated with this device\n",
			mmc_hostname(host), __func__);
		return -EPERM;
	}
EXPORT_SYMBOL(mmc_exit_clk_scaling);

	atomic_set(&host->clk_scaling.devfreq_abort, 0);
	host->clk_scaling.curr_freq = host->ios.clock;
	host->clk_scaling.clk_scaling_in_progress = false;
	host->clk_scaling.need_freq_change = false;

	err = devfreq_resume_device(host->clk_scaling.devfreq);
	if (err) {
		pr_err("%s: %s: failed to resume devfreq (%d)\n",
			mmc_hostname(host), __func__, err);
	} else {
		host->clk_scaling.enable = true;
		pr_debug("%s: devfreq resumed\n", mmc_hostname(host));
	}

	return err;
}
EXPORT_SYMBOL(mmc_resume_clk_scaling);

/**
 * mmc_reset_clk_scale_stats() - reset clock scaling statistics
 * mmc_exit_devfreq_clk_scaling() - Disable clock scaling
 * @host: pointer to mmc host structure
 *
 * Disable clock scaling permanently.
 */
void mmc_reset_clk_scale_stats(struct mmc_host *host)
int mmc_exit_clk_scaling(struct mmc_host *host)
{
	int err;

	if (!host) {
		pr_err("bad host parameter\n");
		pr_err("%s: bad host parameter\n", __func__);
		WARN_ON(1);
		return;
		return -EINVAL;
	}
	if (!host->clk_scaling.enable)
		return;
	spin_lock_bh(&host->clk_scaling.lock);
	host->clk_scaling.total_busy_time_us = 0;
	spin_unlock_bh(&host->clk_scaling.lock);

	if (!mmc_can_scale_clk(host))
		return 0;

	if (!host->clk_scaling.devfreq) {
		pr_err("%s: %s: no devfreq is assosiated with this device\n",
			mmc_hostname(host), __func__);
		return -EPERM;
	}

	err = mmc_suspend_clk_scaling(host);
	if (err) {
		pr_err("%s: %s: fail to suspend clock scaling (%d)\n",
			mmc_hostname(host), __func__,  err);
		return err;
	}

	err = devfreq_remove_device(host->clk_scaling.devfreq);
	if (err) {
		pr_err("%s: remove devfreq failed (%d)\n",
			mmc_hostname(host), err);
		return err;
	}

	host->clk_scaling.devfreq = NULL;
	atomic_set(&host->clk_scaling.devfreq_abort, 1);
	pr_debug("%s: devfreq was removed\n", mmc_hostname(host));

	return 0;
}
EXPORT_SYMBOL(mmc_reset_clk_scale_stats);
EXPORT_SYMBOL(mmc_exit_clk_scaling);

/**
 *	mmc_request_done - finish processing an MMC request
@@ -3909,7 +3954,6 @@ int mmc_pm_notify(struct notifier_block *notify_block,
		spin_unlock_irqrestore(&host->lock, flags);
		cancel_delayed_work_sync(&host->detect);

		mmc_disable_clk_scaling(host);
		if (!host->bus_ops)
			break;

+2 −2
Original line number Diff line number Diff line
@@ -72,11 +72,11 @@ void mmc_remove_card_debugfs(struct mmc_card *card);

void mmc_init_context_info(struct mmc_host *host);

extern void mmc_disable_clk_scaling(struct mmc_host *host);
extern bool mmc_can_scale_clk(struct mmc_host *host);
extern int mmc_init_clk_scaling(struct mmc_host *host);
extern int mmc_suspend_clk_scaling(struct mmc_host *host);
extern int mmc_resume_clk_scaling(struct mmc_host *host);
extern int mmc_exit_clk_scaling(struct mmc_host *host);
extern void mmc_reset_clk_scale_stats(struct mmc_host *host);
extern unsigned long mmc_get_max_frequency(struct mmc_host *host);
#endif
+0 −2
Original line number Diff line number Diff line
@@ -168,8 +168,6 @@ void mmc_host_clk_hold(struct mmc_host *host)
		spin_unlock_irqrestore(&host->clk_lock, flags);
		mmc_ungate_clock(host);

		/* Reset clock scaling stats as host is out of idle */
		mmc_reset_clk_scale_stats(host);
		spin_lock_irqsave(&host->clk_lock, flags);
		pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
	}
+25 −17
Original line number Diff line number Diff line
@@ -2210,12 +2210,12 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
	BUG_ON(!host);
	BUG_ON(!host->card);

	/*
	 * Disable clock scaling before suspend and enable it after resume so
	 * as to avoid clock scaling decisions kicking in during this window.
	 */
	if (mmc_can_scale_clk(host))
		mmc_disable_clk_scaling(host);
	err = mmc_suspend_clk_scaling(host);
	if (err) {
		pr_err("%s: %s: fail to suspend clock scaling (%d)\n",
			mmc_hostname(host), __func__, err);
		goto out;
	}

	mmc_claim_host(host);

@@ -2335,12 +2335,10 @@ static int _mmc_resume(struct mmc_host *host)

	mmc_release_host(host);

	/*
	 * We have done full initialization of the card,
	 * reset the clk scale stats and current frequency.
	 */
	if (mmc_can_scale_clk(host))
		mmc_init_clk_scaling(host);
	err = mmc_resume_clk_scaling(host);
	if (err)
		pr_err("%s: %s: fail to resume clock scaling (%d)\n",
			mmc_hostname(host), __func__, err);

out:
	if (!err)
@@ -2416,15 +2414,23 @@ static int mmc_power_restore(struct mmc_host *host)
{
	int ret;

	/* Disable clk scaling to avoid switching frequencies intermittently */
	mmc_disable_clk_scaling(host);
	/* Suspend clk scaling to avoid switching frequencies intermittently */

	ret = mmc_suspend_clk_scaling(host);
	if (ret) {
		pr_err("%s: %s: fail to suspend clock scaling (%d)\n",
			mmc_hostname(host), __func__, ret);
		return ret;
	}

	mmc_claim_host(host);
	ret = mmc_init_card(host, host->card->ocr, host->card);
	mmc_release_host(host);

	if (mmc_can_scale_clk(host))
		mmc_init_clk_scaling(host);
	ret = mmc_resume_clk_scaling(host);
	if (ret)
		pr_err("%s: %s: fail to resume clock scaling (%d)\n",
			mmc_hostname(host), __func__, ret);

	return ret;
}
@@ -2556,7 +2562,9 @@ int mmc_attach_mmc(struct mmc_host *host)
	if (err)
		goto remove_card;

	mmc_init_clk_scaling(host);
	err = mmc_init_clk_scaling(host);
	if (err)
		goto remove_card;

	register_reboot_notifier(&host->card->reboot_notify);

+27 −14
Original line number Diff line number Diff line
@@ -1192,12 +1192,12 @@ static int _mmc_sd_suspend(struct mmc_host *host)
	BUG_ON(!host);
	BUG_ON(!host->card);

	/*
	 * Disable clock scaling before suspend and enable it after resume so
	 * as to avoid clock scaling decisions kicking in during this window.
	 */
	if (mmc_can_scale_clk(host))
		mmc_disable_clk_scaling(host);
	err = mmc_suspend_clk_scaling(host);
	if (err) {
		pr_err("%s: %s: fail to suspend clock scaling (%d)\n",
			mmc_hostname(host), __func__,  err);
		return err;
	}

	mmc_claim_host(host);

@@ -1275,8 +1275,12 @@ static int _mmc_sd_resume(struct mmc_host *host)
#endif
	mmc_card_clr_suspended(host->card);

	if (mmc_can_scale_clk(host))
		mmc_init_clk_scaling(host);
	err = mmc_resume_clk_scaling(host);
	if (err) {
		pr_err("%s: %s: fail to resume clock scaling (%d)\n",
			mmc_hostname(host), __func__, err);
		goto out;
	}

out:
	mmc_release_host(host);
@@ -1340,15 +1344,22 @@ static int mmc_sd_power_restore(struct mmc_host *host)
{
	int ret;

	/* Disable clk scaling to avoid switching frequencies intermittently */
	mmc_disable_clk_scaling(host);
	/* Suspend clk scaling to avoid switching frequencies intermittently */
	ret = mmc_suspend_clk_scaling(host);
	if (ret) {
		pr_err("%s: %s: fail to suspend clock scaling (%d)\n",
			mmc_hostname(host), __func__, ret);
		return ret;
	}

	mmc_claim_host(host);
	ret = mmc_sd_init_card(host, host->card->ocr, host->card);
	mmc_release_host(host);

	if (mmc_can_scale_clk(host))
		mmc_init_clk_scaling(host);
	ret = mmc_resume_clk_scaling(host);
	if (ret)
		pr_err("%s: %s: fail to resume clock scaling (%d)\n",
			mmc_hostname(host), __func__, ret);

	return ret;
}
@@ -1443,7 +1454,9 @@ int mmc_attach_sd(struct mmc_host *host)
	if (err)
		goto remove_card;

	mmc_init_clk_scaling(host);
	err = mmc_init_clk_scaling(host);
	if (err)
		goto remove_card;

	return 0;