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

Commit 6943048a authored by Vijay Viswanath's avatar Vijay Viswanath
Browse files

mmc: host: Add cmdq hci functions for error handling



Add support to decode the register information stored in
errored mrqs. The higher layers can use them to decode the error
information related to hardware and use them to make decisions during
error handling.

Change-Id: I61d739a4976ebdd4ae2b0f745b93c830c959579b
Signed-off-by: default avatarVijay Viswanath <vviswana@codeaurora.org>
parent f67a2861
Loading
Loading
Loading
Loading
+79 −6
Original line number Diff line number Diff line
@@ -761,6 +761,13 @@ static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq)
ring_doorbell:
	/* Ensure the task descriptor list is flushed before ringing doorbell */
	wmb();

	if (test_bit(CMDQ_STATE_ERR, &mmc->cmdq_ctx.curr_state)) {
		pr_err("%s: %s: CQ in err state, ending current req\n",
			mmc_hostname(mmc), __func__);
		return 0;
	}

	if (cmdq_readl(cq_host, CQTDBR) & (1 << tag)) {
		cmdq_dumpregs(cq_host);
		BUG_ON(1);
@@ -796,10 +803,10 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag)
irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
{
	u32 status;
	unsigned long tag = 0, comp_status;
	unsigned long tag = 0, err_tag = 0, comp_status = 0;
	struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
	unsigned long err_info = 0;
	struct mmc_request *mrq;
	struct mmc_request *mrq = NULL, *err_mrq;
	int ret;
	u32 dbr_set = 0;

@@ -886,7 +893,7 @@ irqreturn_t cmdq_irq(struct mmc_host *mmc, int err)
				mrq->cmd->error = err;
			else
				mrq->data->error = err;
		} else if (err_info & CQ_DTEFV) {
		} else {
			tag = GET_DAT_ERR_TAG(err_info);
			pr_err("%s: Dat err  tag: %lu\n", __func__, tag);
			mrq = get_req_by_tag(cq_host, tag);
@@ -913,6 +920,7 @@ skip_cqterri:
		 * CQE detected a reponse error from device
		 * In most cases, this would require a reset.
		 */
		comp_status = cmdq_readl(cq_host, CQTCN);
		if (status & CQIS_RED) {
			/*
			 * will check if the RED error is due to a bkops
@@ -926,10 +934,31 @@ skip_cqterri:
			mrq->cmdq_req->resp_err = true;
			pr_err("%s: Response error (0x%08x) from card !!!",
				mmc_hostname(mmc), cmdq_readl(cq_host, CQCRA));
		} else {

			/*
			 * If RED error is detected for WP violation, there is
			 * a chance that the error occurred on the previous
			 * executed task which has a completion notification.
			 * So handle request completion in error handler
			 */
			if (cmdq_readl(cq_host, CQCRA) & CQ_WP_RED) {
				for_each_set_bit(err_tag, &comp_status,
						cq_host->num_slots) {
					/* set err the corresponding mrq */
					err_mrq = get_req_by_tag(cq_host,
							err_tag);
					err_mrq->cmdq_req->resp_err = true;
				}
			}
		}
		/*
		 * The following register info are needed for error recovery
		 */
		mrq->cmdq_req->resp_idx = cmdq_readl(cq_host, CQCRI);
		mrq->cmdq_req->resp_arg = cmdq_readl(cq_host, CQCRA);
		}
		mrq->cmdq_req->dev_pend = cmdq_readl(cq_host, CQDPT);
		mrq->cmdq_req->err_info = err_info;
		mrq->cmdq_req->cqtcn = comp_status;

		cmdq_finish_data(mmc, tag);
	} else {
@@ -964,6 +993,9 @@ skip_cqterri:
				MMC_TRACE(mmc, "%s: completing tag -> %lu\n",
					__func__, tag);
				cmdq_finish_data(mmc, tag);
			} else {
				pr_err("%s: tag:%lu finish_data already done\n",
						mmc_hostname(mmc), tag);
			}
		}
	}
@@ -1125,6 +1157,45 @@ static void cmdq_dumpstate(struct mmc_host *mmc)
	cmdq_runtime_pm_put(cq_host);
}

static struct mmc_request *cmdq_get_mrq_by_tag(struct mmc_host *mmc, int tag)
{
	struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
	struct mmc_request *mrq = get_req_by_tag(cq_host, tag);

	return mrq;
}

static void cmdq_err_info(struct mmc_host *mmc,
		struct mmc_cmdq_err_info *err_data, struct mmc_request *mrq) {

	err_data->remove_task = false;
	err_data->fail_comp_task = false;
	err_data->fail_dev_pend = false;
	err_data->timedout = false;
	err_data->max_slot = NUM_SLOTS;
	err_data->dcmd_slot = DCMD_SLOT;

	err_data->comp_status = mrq->cmdq_req->cqtcn;
	err_data->cq_terri = mrq->cmdq_req->err_info;
	err_data->dev_pend = mrq->cmdq_req->dev_pend;
	err_data->resp_err = mrq->cmdq_req->resp_err;
	err_data->tag = mrq->cmdq_req->tag;

	mrq->cmdq_req->cqtcn = 0;
	mrq->cmdq_req->err_info = 0;
	mrq->cmdq_req->dev_pend = 0;
	if (mrq->cmdq_req->resp_err)
		mrq->cmdq_req->resp_err = false;

	err_data->data_cmd = GET_DAT_ERR_CMD(err_data->cq_terri);
	err_data->data_tag = GET_DAT_ERR_TAG(err_data->cq_terri);
	err_data->data_valid = (err_data->cq_terri & CQ_DTEFV);

	err_data->cmd = GET_CMD_ERR_CMD(err_data->cq_terri);
	err_data->cmd_tag = GET_CMD_ERR_TAG(err_data->cq_terri);
	err_data->cmd_valid = (err_data->cq_terri & CQ_RMEFV);
}

static int cmdq_late_init(struct mmc_host *mmc)
{
	struct sdhci_host *host = mmc_priv(mmc);
@@ -1152,6 +1223,8 @@ static const struct mmc_cmdq_host_ops cmdq_host_ops = {
	.halt = cmdq_halt,
	.reset	= cmdq_reset,
	.dumpstate = cmdq_dumpstate,
	.err_info = cmdq_err_info,
	.get_mrq_by_tag = cmdq_get_mrq_by_tag,
};

struct cmdq_host *cmdq_pltfm_init(struct platform_device *pdev)
+2 −0
Original line number Diff line number Diff line
@@ -103,6 +103,8 @@

#define GET_CMD_ERR_TAG(__r__) ((__r__ & CQ_RMETI) >> 8)
#define GET_DAT_ERR_TAG(__r__) ((__r__ & CQ_DTETI) >> 24)
#define GET_CMD_ERR_CMD(__r__) (__r__ & 0x3F)
#define GET_DAT_ERR_CMD(__r__) ((__r__ & 0x3F0000) >> 16)

/* command response index */
#define CQCRI		0x58
+42 −1
Original line number Diff line number Diff line
@@ -90,6 +90,41 @@ enum mmc_load {
	MMC_LOAD_LOW,
};

/* RED error flags to detect type of RED error */
#define CQ_CMD_RED_ERR	(R1_BLOCK_LEN_ERROR | R1_ERASE_SEQ_ERROR | \
		R1_ERASE_PARAM | R1_LOCK_UNLOCK_FAILED | R1_ILLEGAL_COMMAND | \
		R1_CID_CSD_OVERWRITE | R1_SWITCH_ERROR)

#define CQ_WP_RED	(R1_WP_VIOLATION | R1_WP_ERASE_SKIP)

#define CQ_RED_RETRY	(R1_COM_CRC_ERROR | R1_CARD_ECC_FAILED | R1_CC_ERROR |\
		R1_ERROR | R1_ERASE_RESET | R1_EXCEPTION_EVENT)

#define CQ_ADDR_ERR	(R1_OUT_OF_RANGE | R1_ADDRESS_ERROR)

#define CQ_RED	(CQ_WP_RED | CQ_CMD_RED_ERR | CQ_RED_RETRY | CQ_ADDR_ERR)

struct mmc_cmdq_err_info {
	bool remove_task;
	bool fail_comp_task;
	bool fail_dev_pend;
	bool timedout;
	unsigned long comp_status;
	u32 cq_terri;
	unsigned long dev_pend;
	bool resp_err;
	int tag;
	int data_cmd;
	int data_tag;
	bool data_valid;
	int cmd;
	int cmd_tag;
	bool cmd_valid;

	int max_slot;
	int dcmd_slot;
};

struct mmc_cmdq_host_ops {
	int (*init)(struct mmc_host *host);
	int (*enable)(struct mmc_host *host);
@@ -99,6 +134,10 @@ struct mmc_cmdq_host_ops {
	int (*halt)(struct mmc_host *host, bool halt);
	void (*reset)(struct mmc_host *host, bool soft);
	void (*dumpstate)(struct mmc_host *host);
	void (*err_info)(struct mmc_host *host,
			struct mmc_cmdq_err_info *err_data,
			struct mmc_request *mrq);
	struct mmc_request *(*get_mrq_by_tag)(struct mmc_host *mmc, int tag);
};

struct mmc_host_ops {
@@ -201,10 +240,12 @@ struct mmc_cmdq_req {

	unsigned int		resp_idx;
	unsigned int		resp_arg;
	unsigned int		dev_pend_tasks;
	unsigned int		dev_pend;
	bool			resp_err;
	int			tag; /* used for command queuing */
	u8			ctx_id;
	u32			err_info;
	unsigned long		cqtcn;
};

struct mmc_async_req {
+6 −0
Original line number Diff line number Diff line
@@ -65,4 +65,10 @@
#define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
#define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1  */

  /* class 11 */
#define MMC_CMDQ_TASK_PARAM	 44   /* ac			 R1  */
#define MMC_CMDQ_TASK_ADDR	 45   /* ac   [31:0] blk addr    R1  */
#define MMC_CMDQ_READ_TASK	 46   /* adtc [20:16] Task ID    R1  */
#define MMC_CMDQ_WRITE_TASK	 47   /* adtc [20:16] Task ID    R1  */

#endif /* UAPI_MMC_MMC_H */