diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 6dad4673090f..120e4577b678 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2912,6 +2912,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; } @@ -3487,6 +3496,32 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *req) } if (req) { + 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(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)) @@ -3494,19 +3529,6 @@ static int mmc_blk_cmdq_issue_rq(struct mmc_queue *mq, struct request *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)); - if (ret) { - pr_err("%s: failed while waiting for the CMDQ to be empty %s err (%d)\n", - mmc_hostname(card->host), - __func__, ret); - BUG_ON(1); - } - } - ret = mmc_blk_cmdq_issue_flush_rq(mq, req); } else { ret = mmc_blk_cmdq_issue_rw_rq(mq, req); @@ -3975,7 +3997,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 diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 2574e8af91fe..5ee1a379b82b 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -335,6 +335,8 @@ enum mmc_pon_type { MMC_SHRT_PON, }; +#define MMC_QUIRK_CMDQ_DELAY_BEFORE_DCMD 6 /* microseconds */ + /* * MMC device */ @@ -388,8 +390,8 @@ struct mmc_card { #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 */ diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 959713837423..6dd6add52d64 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -260,6 +260,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; }; /**