mmc: core: Support zeroout using TRIM for eMMC
If an eMMC card supports TRIM and indicates that it erases to zeros, we can use it to support hardware offloading of REQ_OP_WRITE_ZEROES, so let's add support for this. Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com> Reviewed-by: Avri Altman <Avri.Altman@wdc.com> Link: https://lore.kernel.org/r/20220429152118.3617303-1-vincent.whitchurch@axis.com Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
parent
0c9ee5ba75
commit
f7b6fc3273
|
@ -126,6 +126,7 @@ struct mmc_blk_data {
|
|||
#define MMC_BLK_DISCARD BIT(2)
|
||||
#define MMC_BLK_SECDISCARD BIT(3)
|
||||
#define MMC_BLK_CQE_RECOVERY BIT(4)
|
||||
#define MMC_BLK_TRIM BIT(5)
|
||||
|
||||
/*
|
||||
* Only set in main mmc_blk_data associated
|
||||
|
@ -1092,12 +1093,13 @@ static void mmc_blk_issue_drv_op(struct mmc_queue *mq, struct request *req)
|
|||
blk_mq_end_request(req, ret ? BLK_STS_IOERR : BLK_STS_OK);
|
||||
}
|
||||
|
||||
static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
|
||||
static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req,
|
||||
int type, unsigned int erase_arg)
|
||||
{
|
||||
struct mmc_blk_data *md = mq->blkdata;
|
||||
struct mmc_card *card = md->queue.card;
|
||||
unsigned int from, nr;
|
||||
int err = 0, type = MMC_BLK_DISCARD;
|
||||
int err = 0;
|
||||
blk_status_t status = BLK_STS_OK;
|
||||
|
||||
if (!mmc_can_erase(card)) {
|
||||
|
@ -1113,13 +1115,13 @@ static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
|
|||
if (card->quirks & MMC_QUIRK_INAND_CMD38) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
INAND_CMD38_ARG_EXT_CSD,
|
||||
card->erase_arg == MMC_TRIM_ARG ?
|
||||
erase_arg == MMC_TRIM_ARG ?
|
||||
INAND_CMD38_ARG_TRIM :
|
||||
INAND_CMD38_ARG_ERASE,
|
||||
card->ext_csd.generic_cmd6_time);
|
||||
}
|
||||
if (!err)
|
||||
err = mmc_erase(card, from, nr, card->erase_arg);
|
||||
err = mmc_erase(card, from, nr, erase_arg);
|
||||
} while (err == -EIO && !mmc_blk_reset(md, card->host, type));
|
||||
if (err)
|
||||
status = BLK_STS_IOERR;
|
||||
|
@ -1129,6 +1131,19 @@ fail:
|
|||
blk_mq_end_request(req, status);
|
||||
}
|
||||
|
||||
static void mmc_blk_issue_trim_rq(struct mmc_queue *mq, struct request *req)
|
||||
{
|
||||
mmc_blk_issue_erase_rq(mq, req, MMC_BLK_TRIM, MMC_TRIM_ARG);
|
||||
}
|
||||
|
||||
static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
|
||||
{
|
||||
struct mmc_blk_data *md = mq->blkdata;
|
||||
struct mmc_card *card = md->queue.card;
|
||||
|
||||
mmc_blk_issue_erase_rq(mq, req, MMC_BLK_DISCARD, card->erase_arg);
|
||||
}
|
||||
|
||||
static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
|
||||
struct request *req)
|
||||
{
|
||||
|
@ -2329,6 +2344,9 @@ enum mmc_issued mmc_blk_mq_issue_rq(struct mmc_queue *mq, struct request *req)
|
|||
case REQ_OP_SECURE_ERASE:
|
||||
mmc_blk_issue_secdiscard_rq(mq, req);
|
||||
break;
|
||||
case REQ_OP_WRITE_ZEROES:
|
||||
mmc_blk_issue_trim_rq(mq, req);
|
||||
break;
|
||||
case REQ_OP_FLUSH:
|
||||
mmc_blk_issue_flush(mq, req);
|
||||
break;
|
||||
|
|
|
@ -191,6 +191,8 @@ static void mmc_queue_setup_discard(struct request_queue *q,
|
|||
q->limits.discard_granularity = SECTOR_SIZE;
|
||||
if (mmc_can_secure_erase_trim(card))
|
||||
blk_queue_flag_set(QUEUE_FLAG_SECERASE, q);
|
||||
if (mmc_can_trim(card) && card->erased_byte == 0)
|
||||
blk_queue_max_write_zeroes_sectors(q, max_discard);
|
||||
}
|
||||
|
||||
static unsigned short mmc_get_max_segments(struct mmc_host *host)
|
||||
|
|
Loading…
Reference in New Issue