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

Commit 7ecbbe01 authored by Subhash Jadavani's avatar Subhash Jadavani
Browse files

mmc: block: workaround for timeout issue with some vendor devices



Commit 66a7393a ("mmc: block: ensure CMDQ
is empty before queuing cache flush") added a workaround for particular
vendor's eMMC devices. Workaround was to wait for all the outstanding
requests to finish up before queuing the flush request. Now detailed
root cause analysis from vendor shows that original issue can happen only
if DCMD command is sent to device too quickly (within less than 6
microseconds) after completion of previous small sector (less than 8
sectors) read operations. Hence with this change, we are fine tuning the
previous workaround such that it would almost have no impact on the storage
benchmark performance numbers.

Change-Id: I1df1c5d7bbcd7b526236651077b7dade2626cb30
Signed-off-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
parent aa3aa09a
Loading
Loading
Loading
Loading
+36 −14
Original line number Diff line number Diff line
@@ -2823,6 +2823,15 @@ static int mmc_blk_cmdq_issue_rw_rq(struct mmc_queue *mq, struct request *req)
	mc_rq = mmc_blk_cmdq_rw_prep(active_mqrq, mq);

	ret = mmc_blk_cmdq_start_req(card->host, mc_rq);

	if (!ret && (card->quirks & MMC_QUIRK_CMDQ_EMPTY_BEFORE_DCMD)) {
		unsigned int sectors = blk_rq_sectors(req);

		if (((sectors > 0) && (sectors < 8))
		    && (rq_data_dir(req) == READ))
			host->cmdq_ctx.active_small_sector_read_reqs++;
	}

	return ret;
}

@@ -3396,26 +3405,39 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req)
	}

	if (req) {
		if (cmd_flags & REQ_DISCARD) {
			if (cmd_flags & REQ_SECURE &&
			   !(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN))
				ret = mmc_blk_cmdq_issue_secdiscard_rq(mq, req);
			else
				ret = mmc_blk_cmdq_issue_discard_rq(mq, req);
		} else if (cmd_flags & REQ_FLUSH) {
			if (card->quirks &
			    MMC_QUIRK_CMDQ_EMPTY_BEFORE_FLUSH) {
				ret = wait_event_interruptible(
					card->host->cmdq_ctx.queue_empty_wq,
					(!card->host->cmdq_ctx.active_reqs));
		struct mmc_host *host = card->host;
		struct mmc_cmdq_context_info *ctx = &host->cmdq_ctx;

		if ((cmd_flags & (REQ_FLUSH | REQ_DISCARD)) &&
		    (card->quirks & MMC_QUIRK_CMDQ_EMPTY_BEFORE_DCMD) &&
		    ctx->active_small_sector_read_reqs) {
			ret = wait_event_interruptible(ctx->queue_empty_wq,
						      !ctx->active_reqs);
			if (ret) {
				pr_err("%s: failed while waiting for the CMDQ to be empty %s err (%d)\n",
						mmc_hostname(card->host),
					mmc_hostname(host),
					__func__, ret);
				BUG_ON(1);
			}
			/* clear the counter now */
			ctx->active_small_sector_read_reqs = 0;
			/*
			 * If there were small sector (less than 8 sectors) read
			 * operations in progress then we have to wait for the
			 * outstanding requests to finish and should also have
			 * atleast 6 microseconds delay before queuing the DCMD
			 * request.
			 */
			udelay(MMC_QUIRK_CMDQ_DELAY_BEFORE_DCMD);
		}

		if (cmd_flags & REQ_DISCARD) {
			if (cmd_flags & REQ_SECURE &&
			   !(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN))
				ret = mmc_blk_cmdq_issue_secdiscard_rq(mq, req);
			else
				ret = mmc_blk_cmdq_issue_discard_rq(mq, req);
		} else if (cmd_flags & REQ_FLUSH) {
			ret = mmc_blk_cmdq_issue_flush_rq(mq, req);
		} else {
			ret = mmc_blk_cmdq_issue_rw_rq(mq, req);
@@ -3874,7 +3896,7 @@ static const struct mmc_fixup blk_fixups[] =
	MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
		  MMC_QUIRK_BLK_NO_CMD23),
	MMC_FIXUP(CID_NAME_ANY, CID_MANFID_TOSHIBA, CID_OEMID_ANY,
		  add_quirk_mmc, MMC_QUIRK_CMDQ_EMPTY_BEFORE_FLUSH),
		  add_quirk_mmc, MMC_QUIRK_CMDQ_EMPTY_BEFORE_DCMD),

	/*
	 * Some Micron MMC cards needs longer data read timeout than
+4 −2
Original line number Diff line number Diff line
@@ -332,6 +332,8 @@ enum mmc_pon_type {
	MMC_SHRT_PON,
};

#define MMC_QUIRK_CMDQ_DELAY_BEFORE_DCMD 6 /* microseconds */

/*
 * MMC device
 */
@@ -383,8 +385,8 @@ struct mmc_card {
#define MMC_QUIRK_QCA6574_SETTINGS (1 << 15)	/* QCA6574 card settings*/
#define MMC_QUIRK_QCA9377_SETTINGS (1 << 16)	/* QCA9377 card settings*/

/* Make sure CMDQ is empty before queuing cache flush */
#define MMC_QUIRK_CMDQ_EMPTY_BEFORE_FLUSH (1 << 17)
/* Make sure CMDQ is empty before queuing DCMD */
#define MMC_QUIRK_CMDQ_EMPTY_BEFORE_DCMD (1 << 17)

	unsigned int		erase_size;	/* erase size in sectors */
 	unsigned int		erase_shift;	/* if erase unit is power 2 */
+1 −0
Original line number Diff line number Diff line
@@ -258,6 +258,7 @@ struct mmc_cmdq_context_info {
#define	CMDQ_STATE_HALT 2
	wait_queue_head_t	queue_empty_wq;
	wait_queue_head_t	wait;
	int active_small_sector_read_reqs;
};

/**