Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Vincent Whitchurch and committed by
Ulf Hansson
f7b6fc32 0c9ee5ba

+24 -4
+22 -4
drivers/mmc/core/block.c
··· 126 126 #define MMC_BLK_DISCARD BIT(2) 127 127 #define MMC_BLK_SECDISCARD BIT(3) 128 128 #define MMC_BLK_CQE_RECOVERY BIT(4) 129 + #define MMC_BLK_TRIM BIT(5) 129 130 130 131 /* 131 132 * Only set in main mmc_blk_data associated ··· 1093 1092 blk_mq_end_request(req, ret ? BLK_STS_IOERR : BLK_STS_OK); 1094 1093 } 1095 1094 1096 - static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) 1095 + static void mmc_blk_issue_erase_rq(struct mmc_queue *mq, struct request *req, 1096 + int type, unsigned int erase_arg) 1097 1097 { 1098 1098 struct mmc_blk_data *md = mq->blkdata; 1099 1099 struct mmc_card *card = md->queue.card; 1100 1100 unsigned int from, nr; 1101 - int err = 0, type = MMC_BLK_DISCARD; 1101 + int err = 0; 1102 1102 blk_status_t status = BLK_STS_OK; 1103 1103 1104 1104 if (!mmc_can_erase(card)) { ··· 1115 1113 if (card->quirks & MMC_QUIRK_INAND_CMD38) { 1116 1114 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 1117 1115 INAND_CMD38_ARG_EXT_CSD, 1118 - card->erase_arg == MMC_TRIM_ARG ? 1116 + erase_arg == MMC_TRIM_ARG ? 1119 1117 INAND_CMD38_ARG_TRIM : 1120 1118 INAND_CMD38_ARG_ERASE, 1121 1119 card->ext_csd.generic_cmd6_time); 1122 1120 } 1123 1121 if (!err) 1124 - err = mmc_erase(card, from, nr, card->erase_arg); 1122 + err = mmc_erase(card, from, nr, erase_arg); 1125 1123 } while (err == -EIO && !mmc_blk_reset(md, card->host, type)); 1126 1124 if (err) 1127 1125 status = BLK_STS_IOERR; ··· 1129 1127 mmc_blk_reset_success(md, type); 1130 1128 fail: 1131 1129 blk_mq_end_request(req, status); 1130 + } 1131 + 1132 + static void mmc_blk_issue_trim_rq(struct mmc_queue *mq, struct request *req) 1133 + { 1134 + mmc_blk_issue_erase_rq(mq, req, MMC_BLK_TRIM, MMC_TRIM_ARG); 1135 + } 1136 + 1137 + static void mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) 1138 + { 1139 + struct mmc_blk_data *md = mq->blkdata; 1140 + struct mmc_card *card = md->queue.card; 1141 + 1142 + mmc_blk_issue_erase_rq(mq, req, MMC_BLK_DISCARD, card->erase_arg); 1132 1143 } 1133 1144 1134 1145 static void mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, ··· 2343 2328 break; 2344 2329 case REQ_OP_SECURE_ERASE: 2345 2330 mmc_blk_issue_secdiscard_rq(mq, req); 2331 + break; 2332 + case REQ_OP_WRITE_ZEROES: 2333 + mmc_blk_issue_trim_rq(mq, req); 2346 2334 break; 2347 2335 case REQ_OP_FLUSH: 2348 2336 mmc_blk_issue_flush(mq, req);
+2
drivers/mmc/core/queue.c
··· 191 191 q->limits.discard_granularity = SECTOR_SIZE; 192 192 if (mmc_can_secure_erase_trim(card)) 193 193 blk_queue_flag_set(QUEUE_FLAG_SECERASE, q); 194 + if (mmc_can_trim(card) && card->erased_byte == 0) 195 + blk_queue_max_write_zeroes_sectors(q, max_discard); 194 196 } 195 197 196 198 static unsigned short mmc_get_max_segments(struct mmc_host *host)