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

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

Merge "mmc: cmdq_hci: Helper API/info in cmdq for halt"

parents db2d2d2b 8b0af332
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@
/* 1 sec */
#define HALT_TIMEOUT_MS 1000

static int cmdq_halt_poll(struct mmc_host *mmc);

#ifdef CONFIG_PM_RUNTIME
static int cmdq_runtime_pm_get(struct cmdq_host *host)
{
@@ -116,6 +118,20 @@ static void setup_trans_desc(struct cmdq_host *cq_host, u8 tag)
	}
}

static void cmdq_set_halt_irq(struct cmdq_host *cq_host, bool enable)
{
	u32 ier;

	ier = cmdq_readl(cq_host, CQISTE);
	if (enable) {
		cmdq_writel(cq_host, ier | HALT, CQISTE);
		cmdq_writel(cq_host, ier | HALT, CQISGE);
	} else {
		cmdq_writel(cq_host, ier & ~HALT, CQISTE);
		cmdq_writel(cq_host, ier & ~HALT, CQISGE);
	}
}

static void cmdq_clear_set_irqs(struct cmdq_host *cq_host, u32 clear, u32 set)
{
	u32 ier;
@@ -369,6 +385,7 @@ static int cmdq_enable(struct mmc_host *mmc)
	mb();

	cq_host->enabled = true;
	mmc_host_clr_cq_disable(mmc);

	if (cq_host->ops->set_block_size)
		cq_host->ops->set_block_size(cq_host->mmc);
@@ -403,6 +420,7 @@ static void cmdq_disable(struct mmc_host *mmc, bool soft)

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

static void cmdq_reset(struct mmc_host *mmc, bool soft)
@@ -448,6 +466,7 @@ static void cmdq_reset(struct mmc_host *mmc, bool soft)
	cmdq_writel(cq_host, cqcfg, CQCFG);
	cmdq_runtime_pm_put(cq_host);
	cq_host->enabled = true;
	mmc_host_clr_cq_disable(mmc);
}

static void cmdq_prep_task_desc(struct mmc_request *mrq,
@@ -729,6 +748,7 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
	struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
	unsigned long err_info = 0;
	struct mmc_request *mrq;
	int ret;

	status = cmdq_readl(cq_host, CQIS);
	cmdq_writel(cq_host, status, CQIS);
@@ -741,6 +761,17 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
		pr_err("%s: err: %d status: 0x%08x task-err-info (0x%08lx)\n",
		       mmc_hostname(mmc), err, status, err_info);

		/*
		 * Need to halt CQE in case of error in interrupt context itself
		 * otherwise CQE may proceed with sending CMD to device even if
		 * CQE/card is in error state.
		 * CMDQ error handling will make sure that it is unhalted after
		 * handling all the errors.
		 */
		ret = cmdq_halt_poll(mmc);
		if (ret)
			pr_err("%s: %s: halt failed ret=%d\n",
					mmc_hostname(mmc), __func__, ret);
		cmdq_dumpregs(cq_host);

		if (err_info & CQ_RMEFV) {
@@ -823,6 +854,38 @@ out:
}
EXPORT_SYMBOL(cmdq_irq);

/* cmdq_halt_poll - Halting CQE using polling method.
 * @mmc: struct mmc_host
 * This is used mainly from interrupt context to halt
 * CQE engine.
 */
static int cmdq_halt_poll(struct mmc_host *mmc)
{
	struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
	int retries = 100;

	cmdq_set_halt_irq(cq_host, false);
	cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) | HALT, CQCTL);
	while (retries) {
		if (!(cmdq_readl(cq_host, CQCTL) & HALT)) {
			udelay(5);
			retries--;
			continue;
		} else {
			if (cq_host->ops->post_cqe_halt)
				cq_host->ops->post_cqe_halt(mmc);
			/* halt done: re-enable legacy interrupts */
			if (cq_host->ops->clear_set_irqs)
				cq_host->ops->clear_set_irqs(mmc,
							false);
			mmc_host_set_halt(mmc);
			break;
		}
	}
	cmdq_set_halt_irq(cq_host, true);
	return retries ? 0 : -ETIMEDOUT;
}

/* May sleep */
static int cmdq_halt(struct mmc_host *mmc, bool halt)
{
@@ -965,6 +1028,8 @@ int cmdq_init(struct cmdq_host *cq_host, struct mmc_host *mmc,
	cq_host->dcmd_slot = DCMD_SLOT;

	mmc->cmdq_ops = &cmdq_host_ops;
	mmc->num_cq_slots = NUM_SLOTS;
	mmc->dcmd_cq_slot = DCMD_SLOT;

	cq_host->mrq_slot = kzalloc(sizeof(cq_host->mrq_slot) *
				    cq_host->num_slots, GFP_KERNEL);
+3 −1
Original line number Diff line number Diff line
@@ -3099,19 +3099,21 @@ static irqreturn_t sdhci_cmdq_irq(struct sdhci_host *host, u32 intmask)
{
	int err = 0;
	u32 mask = 0;
	irqreturn_t ret;

	if (intmask & SDHCI_INT_CMD_MASK)
		err = sdhci_get_cmd_err(intmask);
	else if (intmask & SDHCI_INT_DATA_MASK)
		err = sdhci_get_data_err(intmask);

	ret = cmdq_irq(host->mmc, err);
	if (err) {
		/* Clear the error interrupts */
		mask = intmask & SDHCI_INT_ERROR_MASK;
		sdhci_writel(host, mask, SDHCI_INT_STATUS);
	}
	return ret;

	return cmdq_irq(host->mmc, err);
}

#else
+18 −0
Original line number Diff line number Diff line
@@ -256,6 +256,7 @@ struct mmc_cmdq_context_info {
#define	CMDQ_STATE_ERR 0
#define	CMDQ_STATE_DCMD_ACTIVE 1
#define	CMDQ_STATE_HALT 2
#define	CMDQ_STATE_CQ_DISABLE 3
	wait_queue_head_t	queue_empty_wq;
	wait_queue_head_t	wait;
	int active_small_sector_read_reqs;
@@ -557,6 +558,8 @@ struct mmc_host {
	enum dev_state dev_status;
	bool			wakeup_on_idle;
	struct mmc_cmdq_context_info	cmdq_ctx;
	int num_cq_slots;
	int dcmd_cq_slot;
	u32			cmdq_thist_enabled;
	/*
	 * several cmdq supporting host controllers are extensions
@@ -697,6 +700,21 @@ static inline int mmc_host_halt(struct mmc_host *host)
	return test_bit(CMDQ_STATE_HALT, &host->cmdq_ctx.curr_state);
}

static inline void mmc_host_set_cq_disable(struct mmc_host *host)
{
	set_bit(CMDQ_STATE_CQ_DISABLE, &host->cmdq_ctx.curr_state);
}

static inline void mmc_host_clr_cq_disable(struct mmc_host *host)
{
	clear_bit(CMDQ_STATE_CQ_DISABLE, &host->cmdq_ctx.curr_state);
}

static inline int mmc_host_cq_disable(struct mmc_host *host)
{
	return test_bit(CMDQ_STATE_CQ_DISABLE, &host->cmdq_ctx.curr_state);
}

#ifdef CONFIG_MMC_CLKGATE
void mmc_host_clk_hold(struct mmc_host *host);
void mmc_host_clk_release(struct mmc_host *host);