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

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

Merge "mmc: host: Add cmdq hci functions for error handling"

parents 6c72fb21 6943048a
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 */