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

Commit b715bdef 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: Add CQE WA for CQE HW bugs"

parents 51d60f09 c2514521
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -99,6 +99,8 @@ static inline void mmc_cmdq_ready_wait(struct mmc_host *host,
		  && test_bit(CMDQ_STATE_DCMD_ACTIVE, &ctx->curr_state))
		&& !(!host->card->part_curr && !mmc_card_suspended(host->card)
		     && mmc_host_halt(host))
		&& !(!host->card->part_curr && mmc_host_cq_disable(host) &&
			!mmc_card_suspended(host->card))
		&& !test_bit(CMDQ_STATE_ERR, &ctx->curr_state)
		&& !mmc_check_blk_queue_start_tag(q, mq->cmdq_req_peeked));
}
+68 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
#define HALT_TIMEOUT_MS 1000

static int cmdq_halt_poll(struct mmc_host *mmc);
static int cmdq_halt(struct mmc_host *mmc, bool halt);

#ifdef CONFIG_PM_RUNTIME
static int cmdq_runtime_pm_get(struct cmdq_host *host)
@@ -173,6 +174,27 @@ static void cmdq_dump_task_history(struct cmdq_host *cq_host)
	pr_err("-------------------------\n");
}

static void cmdq_dump_adma_mem(struct cmdq_host *cq_host)
{
	struct mmc_host *mmc = cq_host->mmc;
	dma_addr_t desc_dma;
	int tag = 0;
	unsigned long data_active_reqs =
		mmc->cmdq_ctx.data_active_reqs;
	unsigned long desc_size =
		(cq_host->mmc->max_segs * cq_host->trans_desc_len);

	for_each_set_bit(tag, &data_active_reqs, cq_host->num_slots) {
		desc_dma = get_trans_desc_dma(cq_host, tag);
		pr_err("%s: %s: tag = %d, trans_dma(phys) = %pad, trans_desc(virt) = 0x%p\n",
				mmc_hostname(mmc), __func__, tag,
				&desc_dma, get_trans_desc(cq_host, tag));
		print_hex_dump(KERN_ERR, "cmdq-adma:", DUMP_PREFIX_ADDRESS,
				32, 8, get_trans_desc(cq_host, tag),
				(desc_size), false);
	}
}

static void cmdq_dumpregs(struct cmdq_host *cq_host)
{
	struct mmc_host *mmc = cq_host->mmc;
@@ -749,6 +771,7 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
	unsigned long err_info = 0;
	struct mmc_request *mrq;
	int ret;
	u32 dbr_set = 0;

	status = cmdq_readl(cq_host, CQIS);
	cmdq_writel(cq_host, status, CQIS);
@@ -774,6 +797,43 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
					mmc_hostname(mmc), __func__, ret);
		cmdq_dumpregs(cq_host);

		if (!err_info) {
			/*
			 * It may so happen sometimes for few errors(like ADMA)
			 * that HW cannot give CQTERRI info.
			 * Thus below is a HW WA for recovering from such
			 * scenario.
			 * - To halt/disable CQE and do reset_all.
			 *   Since there is no way to know which tag would
			 *   have caused such error, so check for any first
			 *   bit set in doorbell and proceed with an error.
			 */
			dbr_set = cmdq_readl(cq_host, CQTDBR);
			if (!dbr_set) {
				pr_err("%s: spurious/force error interrupt\n",
						mmc_hostname(mmc));
				cmdq_halt(mmc, false);
				mmc_host_clr_halt(mmc);
				return IRQ_HANDLED;
			}

			tag = ffs(dbr_set) - 1;
			pr_err("%s: error tag selected: tag = %lu\n",
					mmc_hostname(mmc), tag);
			mrq = get_req_by_tag(cq_host, tag);
			if (mrq->data)
				mrq->data->error = err;
			else
				mrq->cmd->error = err;
			/*
			 * Get ADMA descriptor memory in case of ADMA
			 * error for debug.
			 */
			if (err == -EIO)
				cmdq_dump_adma_mem(cq_host);
			goto skip_cqterri;
		}

		if (err_info & CQ_RMEFV) {
			tag = GET_CMD_ERR_TAG(err_info);
			pr_err("%s: CMD err tag: %lu\n", __func__, tag);
@@ -791,6 +851,14 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
			mrq->data->error = err;
		}

skip_cqterri:
		/*
		 * If CQE halt fails then, disable CQE
		 * from processing any further requests
		 */
		if (ret)
			cmdq_disable(mmc, true);

		/*
		 * CQE detected a reponse error from device
		 * In most cases, this would require a reset.