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

Commit 7f599dc7 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "mmc: block: add card device reference counting for CQ mode"

parents 135e6be0 e0f919a5
Loading
Loading
Loading
Loading
+11 −7
Original line number Diff line number Diff line
@@ -1491,7 +1491,7 @@ out:

	if (test_and_clear_bit(0, &ctx_info->req_starved))
		blk_run_queue(mq->queue);
	mmc_release_host(host);
	mmc_put_card(card);
	return err ? 1 : 0;
}

@@ -1607,7 +1607,7 @@ out:

	if (test_and_clear_bit(0, &ctx_info->req_starved))
		blk_run_queue(mq->queue);
	mmc_release_host(host);
	mmc_put_card(card);
	return err ? 1 : 0;
}

@@ -2839,7 +2839,7 @@ static void mmc_blk_cmdq_shutdown(struct mmc_queue *mq)
		return;
	}

	mmc_claim_host(card->host);
	mmc_get_card(card);
	/* disable CQ mode in card */
	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
			 EXT_CSD_CMDQ, 0,
@@ -2852,7 +2852,7 @@ static void mmc_blk_cmdq_shutdown(struct mmc_queue *mq)
		host->card->cmdq_init = false;
	}
out:
	mmc_release_host(card->host);
	mmc_put_card(card);
}

static enum blk_eh_timer_return mmc_blk_cmdq_req_timed_out(struct request *req)
@@ -2887,6 +2887,7 @@ static void mmc_blk_cmdq_err(struct mmc_queue *mq)
	struct mmc_card *card = mq->card;
	struct mmc_cmdq_context_info *ctx_info = &host->cmdq_ctx;

	pm_runtime_get_sync(&card->dev);
	err = mmc_cmdq_halt(host, true);
	if (err) {
		pr_err("halt: failed: %d\n", err);
@@ -2948,6 +2949,9 @@ unhalt:
	mmc_cmdq_halt(host, false);

out:
	pm_runtime_mark_last_busy(&card->dev);
	pm_runtime_put_autosuspend(&card->dev);

	if (test_and_clear_bit(0, &ctx_info->req_starved))
		blk_run_queue(mrq->req->q);
}
@@ -2999,8 +3003,8 @@ out:
	if (!test_bit(CMDQ_STATE_ERR, &ctx_info->curr_state) &&
			test_and_clear_bit(0, &ctx_info->req_starved))
		blk_run_queue(mq->queue);
	mmc_release_host(host);

	mmc_put_card(host->card);
	if (blk_queue_stopped(mq->queue) && !ctx_info->active_reqs)
		complete(&mq->cmdq_shutdown_complete);
	return;
@@ -3269,14 +3273,14 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req)
	struct mmc_card *card = md->queue.card;
	unsigned int cmd_flags = req ? req->cmd_flags : 0;

	mmc_claim_host(card->host);
	mmc_get_card(card);
	ret = mmc_blk_cmdq_part_switch(card, md);
	if (ret) {
		pr_err("%s: %s: partition switch failed %d\n",
				md->disk->disk_name, __func__, ret);
		if (req)
			blk_end_request_all(req, ret);
		mmc_release_host(card->host);
		mmc_put_card(card);
		goto switch_failure;
	}

+19 −1
Original line number Diff line number Diff line
@@ -2138,6 +2138,19 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
	if (mmc_card_suspended(host->card))
		goto out;

	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 out;
		}
		mmc_host_clk_hold(host);
		host->cmdq_ops->disable(host, true);
		mmc_host_clk_release(host);
	}

	if (mmc_card_doing_bkops(host->card)) {
		err = mmc_stop_bkops(host->card);
		if (err)
@@ -2216,6 +2229,11 @@ static int _mmc_resume(struct mmc_host *host)
		}
		break;
	}
	if (!err && mmc_card_cmdq(host->card)) {
		err = mmc_cmdq_halt(host, false);
		if (err)
			pr_err("%s: un-halt: failed: %d\n", __func__, err);
	}
	mmc_card_clr_suspended(host->card);

	mmc_release_host(host);
@@ -2313,7 +2331,7 @@ static int mmc_runtime_resume(struct mmc_host *host)
	trace_mmc_runtime_resume(mmc_hostname(host), err,
			ktime_to_us(ktime_sub(ktime_get(), start)));

	return 0;
	return err;
}

static int mmc_power_restore(struct mmc_host *host)
+41 −11
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/mmc/mmc.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/pm_runtime.h>

#include "cmdq_hci.h"

@@ -32,6 +33,26 @@
/* 1 sec */
#define HALT_TIMEOUT_MS 1000

#ifdef CONFIG_PM_RUNTIME
static int cmdq_runtime_pm_get(struct cmdq_host *host)
{
	return pm_runtime_get_sync(host->mmc->parent);
}
static int cmdq_runtime_pm_put(struct cmdq_host *host)
{
	pm_runtime_mark_last_busy(host->mmc->parent);
	return pm_runtime_put_autosuspend(host->mmc->parent);
}
#else
static inline int cmdq_runtime_pm_get(struct cmdq_host *host)
{
	return 0;
}
static inline int cmdq_runtime_pm_put(struct cmdq_host *host)
{
	return 0;
}
#endif
static inline struct mmc_request *get_req_by_tag(struct cmdq_host *cq_host,
					  unsigned int tag)
{
@@ -272,6 +293,7 @@ static int cmdq_enable(struct mmc_host *mmc)
	if (cq_host->enabled)
		goto out;

	cmdq_runtime_pm_get(cq_host);
	cqcfg = cmdq_readl(cq_host, CQCFG);
	if (cqcfg & 0x1) {
		pr_info("%s: %s: cq_host is already enabled\n",
@@ -335,6 +357,7 @@ static int cmdq_enable(struct mmc_host *mmc)
		cq_host->ops->clear_set_dumpregs(mmc, 1);

out:
	cmdq_runtime_pm_put(cq_host);
	return err;
}

@@ -342,12 +365,13 @@ static void cmdq_disable(struct mmc_host *mmc, bool soft)
{
	struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);

	cmdq_runtime_pm_get(cq_host);
	if (soft) {
		cmdq_writel(cq_host, cmdq_readl(
				    cq_host, CQCFG) & ~(CQ_ENABLE),
			    CQCFG);
	}

	cmdq_runtime_pm_put(cq_host);
	cq_host->enabled = false;
}

@@ -360,6 +384,7 @@ static void cmdq_reset(struct mmc_host *mmc, bool soft)
	unsigned int rca;
	int ret;

	cmdq_runtime_pm_get(cq_host);
	cqcfg = cmdq_readl(cq_host, CQCFG);
	tdlba = cmdq_readl(cq_host, CQTDLBA);
	tdlbau = cmdq_readl(cq_host, CQTDLBAU);
@@ -391,6 +416,7 @@ static void cmdq_reset(struct mmc_host *mmc, bool soft)
	mb();

	cmdq_writel(cq_host, cqcfg, CQCFG);
	cmdq_runtime_pm_put(cq_host);
	cq_host->enabled = true;
}

@@ -536,7 +562,7 @@ static void cmdq_prep_dcmd_desc(struct mmc_host *mmc,

static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
	int err;
	int err = 0;
	u64 data = 0;
	u64 *task_desc = NULL;
	u32 tag = mrq->cmdq_req->tag;
@@ -549,11 +575,13 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq)
		goto out;
	}

	cmdq_runtime_pm_get(cq_host);

	if (mrq->cmdq_req->cmdq_req_flags & DCMD) {
		cmdq_prep_dcmd_desc(mmc, mrq);
		cq_host->mrq_slot[DCMD_SLOT] = mrq;
		cmdq_writel(cq_host, 1 << DCMD_SLOT, CQTDBR);
		return 0;
		goto out;
	}

	if (cq_host->ops->crypto_cfg) {
@@ -575,7 +603,7 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq)
	if (err) {
		pr_err("%s: %s: failed to setup tx desc: %d\n",
		       mmc_hostname(mmc), __func__, err);
		return err;
		goto out;
	}

	BUG_ON(cmdq_readl(cq_host, CQTDBR) & (1 << tag));
@@ -587,6 +615,7 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq)
	cmdq_writel(cq_host, 1 << tag, CQTDBR);

out:
	cmdq_runtime_pm_put(cq_host);
	return err;
}

@@ -689,26 +718,26 @@ EXPORT_SYMBOL(cmdq_irq);
static int cmdq_halt(struct mmc_host *mmc, bool halt)
{
	struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
	u32 val;
	u32 ret = 0;

	cmdq_runtime_pm_get(cq_host);
	if (halt) {
		cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) | HALT,
			    CQCTL);
		val = wait_for_completion_timeout(&cq_host->halt_comp,
		ret = wait_for_completion_timeout(&cq_host->halt_comp,
					  msecs_to_jiffies(HALT_TIMEOUT_MS));
		/* halt done: re-enable legacy interrupts */
		if (cq_host->ops->clear_set_irqs)
			cq_host->ops->clear_set_irqs(mmc, false);

		return val ? 0 : -ETIMEDOUT;
		ret = ret ? 0 : -ETIMEDOUT;
	} else {
		if (cq_host->ops->clear_set_irqs)
			cq_host->ops->clear_set_irqs(mmc, true);
		cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) & ~HALT,
			    CQCTL);
	}

	return 0;
	cmdq_runtime_pm_put(cq_host);
	return ret;
}

static void cmdq_post_req(struct mmc_host *host, struct mmc_request *mrq,
@@ -731,8 +760,9 @@ static void cmdq_post_req(struct mmc_host *host, struct mmc_request *mrq,
static void cmdq_dumpstate(struct mmc_host *mmc)
{
	struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);

	cmdq_runtime_pm_get(cq_host);
	cmdq_dumpregs(cq_host);
	cmdq_runtime_pm_put(cq_host);
}

static const struct mmc_cmdq_host_ops cmdq_host_ops = {