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_DISCARD BIT(2)
|
||||||
#define MMC_BLK_SECDISCARD BIT(3)
|
#define MMC_BLK_SECDISCARD BIT(3)
|
||||||
#define MMC_BLK_CQE_RECOVERY BIT(4)
|
#define MMC_BLK_CQE_RECOVERY BIT(4)
|
||||||
|
#define MMC_BLK_TRIM BIT(5)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only set in main mmc_blk_data associated
|
* 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);
|
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_blk_data *md = mq->blkdata;
|
||||||
struct mmc_card *card = md->queue.card;
|
struct mmc_card *card = md->queue.card;
|
||||||
unsigned int from, nr;
|
unsigned int from, nr;
|
||||||
int err = 0, type = MMC_BLK_DISCARD;
|
int err = 0;
|
||||||
blk_status_t status = BLK_STS_OK;
|
blk_status_t status = BLK_STS_OK;
|
||||||
|
|
||||||
if (!mmc_can_erase(card)) {
|
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) {
|
if (card->quirks & MMC_QUIRK_INAND_CMD38) {
|
||||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||||
INAND_CMD38_ARG_EXT_CSD,
|
INAND_CMD38_ARG_EXT_CSD,
|
||||||
card->erase_arg == MMC_TRIM_ARG ?
|
erase_arg == MMC_TRIM_ARG ?
|
||||||
INAND_CMD38_ARG_TRIM :
|
INAND_CMD38_ARG_TRIM :
|
||||||
INAND_CMD38_ARG_ERASE,
|
INAND_CMD38_ARG_ERASE,
|
||||||
card->ext_csd.generic_cmd6_time);
|
card->ext_csd.generic_cmd6_time);
|
||||||
}
|
}
|
||||||
if (!err)
|
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));
|
} while (err == -EIO && !mmc_blk_reset(md, card->host, type));
|
||||||
if (err)
|
if (err)
|
||||||
status = BLK_STS_IOERR;
|
status = BLK_STS_IOERR;
|
||||||
|
@ -1129,6 +1131,19 @@ fail:
|
||||||
blk_mq_end_request(req, status);
|
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,
|
static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
|
||||||
struct request *req)
|
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:
|
case REQ_OP_SECURE_ERASE:
|
||||||
mmc_blk_issue_secdiscard_rq(mq, req);
|
mmc_blk_issue_secdiscard_rq(mq, req);
|
||||||
break;
|
break;
|
||||||
|
case REQ_OP_WRITE_ZEROES:
|
||||||
|
mmc_blk_issue_trim_rq(mq, req);
|
||||||
|
break;
|
||||||
case REQ_OP_FLUSH:
|
case REQ_OP_FLUSH:
|
||||||
mmc_blk_issue_flush(mq, req);
|
mmc_blk_issue_flush(mq, req);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -191,6 +191,8 @@ static void mmc_queue_setup_discard(struct request_queue *q,
|
||||||
q->limits.discard_granularity = SECTOR_SIZE;
|
q->limits.discard_granularity = SECTOR_SIZE;
|
||||||
if (mmc_can_secure_erase_trim(card))
|
if (mmc_can_secure_erase_trim(card))
|
||||||
blk_queue_flag_set(QUEUE_FLAG_SECERASE, q);
|
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)
|
static unsigned short mmc_get_max_segments(struct mmc_host *host)
|
||||||
|
|
Loading…
Reference in New Issue