Loading drivers/mmc/card/block.c +26 −2 Original line number Diff line number Diff line Loading @@ -1684,7 +1684,30 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) struct mmc_card *card = md->queue.card; int ret = 0; if (!req) return 0; if (req->cmd_flags & REQ_BARRIER) { /* * If eMMC cache flush policy is set to 1, then the device * shall flush the requests in First-In-First-Out (FIFO) order. * In this case, as per spec, the host must not send any cache * barrier requests as they are redundant and add unnecessary * overhead to both device and host. */ if (card->ext_csd.cache_flush_policy & 1) goto end_req; /* * In case barrier is not supported or enabled in the device, * use flush as a fallback option. */ ret = mmc_cache_barrier(card); if (ret) ret = mmc_flush_cache(card); } else if (req->cmd_flags & REQ_FLUSH) { ret = mmc_flush_cache(card); } if (ret == -ENODEV) { pr_err("%s: %s: restart mmc card", req->rq_disk->disk_name, __func__); Loading @@ -1701,6 +1724,7 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) ret = -EIO; } end_req: blk_end_request_all(req, ret); return ret ? 0 : 1; Loading Loading @@ -3313,7 +3337,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ret = mmc_blk_issue_secdiscard_rq(mq, req); else ret = mmc_blk_issue_discard_rq(mq, req); } else if (cmd_flags & REQ_FLUSH) { } else if (cmd_flags & (REQ_FLUSH | REQ_BARRIER)) { /* complete ongoing async transfer before issuing flush */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); Loading drivers/mmc/core/core.c +34 −0 Original line number Diff line number Diff line Loading @@ -3534,6 +3534,40 @@ int mmc_power_restore_host(struct mmc_host *host) } EXPORT_SYMBOL(mmc_power_restore_host); /* * Add barrier request to the requests in cache */ int mmc_cache_barrier(struct mmc_card *card) { struct mmc_host *host = card->host; int err = 0; if (!card->ext_csd.cache_ctrl || (card->quirks & MMC_QUIRK_CACHE_DISABLE)) goto out; if (!mmc_card_mmc(card)) goto out; if (!card->ext_csd.barrier_en) return -ENOTSUPP; /* * If a device receives maximum supported barrier * requests, a barrier command is treated as a * flush command. Hence, it is betetr to use * flush timeout instead a generic CMD6 timeout */ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_FLUSH_CACHE, 0x2, 0); if (err) pr_err("%s: cache barrier error %d\n", mmc_hostname(host), err); out: return err; } EXPORT_SYMBOL(mmc_cache_barrier); /* * Flush the cache to the non-volatile storage. */ Loading drivers/mmc/core/mmc.c +31 −0 Original line number Diff line number Diff line Loading @@ -660,9 +660,19 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) mmc_hostname(card->host), card->ext_csd.cmdq_depth); } card->ext_csd.barrier_support = ext_csd[EXT_CSD_BARRIER_SUPPORT]; card->ext_csd.cache_flush_policy = ext_csd[EXT_CSD_CACHE_FLUSH_POLICY]; pr_info("%s: cache barrier support %d flush policy %d\n", mmc_hostname(card->host), card->ext_csd.barrier_support, card->ext_csd.cache_flush_policy); } else { card->ext_csd.cmdq_support = 0; card->ext_csd.cmdq_depth = 0; card->ext_csd.barrier_support = 0; card->ext_csd.cache_flush_policy = 0; } out: Loading Loading @@ -1848,6 +1858,27 @@ reinit: } else { card->ext_csd.cache_ctrl = 1; } /* enable cache barrier if supported by the device */ if (card->ext_csd.cache_ctrl && card->ext_csd.barrier_support) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BARRIER_CTRL, 1, card->ext_csd.generic_cmd6_time); if (err && err != -EBADMSG) { pr_err("%s: %s: mmc_switch() for BARRIER_CTRL fails %d\n", mmc_hostname(host), __func__, err); goto free_card; } if (err) { pr_warn("%s: Barrier is supported but failed to turn on (%d)\n", mmc_hostname(card->host), err); card->ext_csd.barrier_en = 0; err = 0; } else { card->ext_csd.barrier_en = 1; } } } else { /* * mmc standard doesn't say what is the card default Loading include/linux/mmc/card.h +3 −0 Original line number Diff line number Diff line Loading @@ -116,10 +116,13 @@ struct mmc_ext_csd { u8 raw_pwr_cl_ddr_52_195; /* 238 */ u8 raw_pwr_cl_ddr_52_360; /* 239 */ u8 raw_pwr_cl_ddr_200_360; /* 253 */ u8 cache_flush_policy; /* 240 */ u8 raw_bkops_status; /* 246 */ u8 raw_sectors[4]; /* 212 - 4 bytes */ u8 cmdq_depth; /* 307 */ u8 cmdq_support; /* 308 */ u8 barrier_support; /* 486 */ u8 barrier_en; unsigned int feature_support; #define MMC_DISCARD_FEATURE BIT(0) /* CMD38 feature */ Loading include/linux/mmc/core.h +1 −0 Original line number Diff line number Diff line Loading @@ -186,6 +186,7 @@ extern void mmc_put_card(struct mmc_card *card); extern void mmc_set_ios(struct mmc_host *host); extern int mmc_flush_cache(struct mmc_card *); extern int mmc_cache_barrier(struct mmc_card *); extern int mmc_detect_card_removed(struct mmc_host *host); Loading Loading
drivers/mmc/card/block.c +26 −2 Original line number Diff line number Diff line Loading @@ -1684,7 +1684,30 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) struct mmc_card *card = md->queue.card; int ret = 0; if (!req) return 0; if (req->cmd_flags & REQ_BARRIER) { /* * If eMMC cache flush policy is set to 1, then the device * shall flush the requests in First-In-First-Out (FIFO) order. * In this case, as per spec, the host must not send any cache * barrier requests as they are redundant and add unnecessary * overhead to both device and host. */ if (card->ext_csd.cache_flush_policy & 1) goto end_req; /* * In case barrier is not supported or enabled in the device, * use flush as a fallback option. */ ret = mmc_cache_barrier(card); if (ret) ret = mmc_flush_cache(card); } else if (req->cmd_flags & REQ_FLUSH) { ret = mmc_flush_cache(card); } if (ret == -ENODEV) { pr_err("%s: %s: restart mmc card", req->rq_disk->disk_name, __func__); Loading @@ -1701,6 +1724,7 @@ static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) ret = -EIO; } end_req: blk_end_request_all(req, ret); return ret ? 0 : 1; Loading Loading @@ -3313,7 +3337,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ret = mmc_blk_issue_secdiscard_rq(mq, req); else ret = mmc_blk_issue_discard_rq(mq, req); } else if (cmd_flags & REQ_FLUSH) { } else if (cmd_flags & (REQ_FLUSH | REQ_BARRIER)) { /* complete ongoing async transfer before issuing flush */ if (card->host->areq) mmc_blk_issue_rw_rq(mq, NULL); Loading
drivers/mmc/core/core.c +34 −0 Original line number Diff line number Diff line Loading @@ -3534,6 +3534,40 @@ int mmc_power_restore_host(struct mmc_host *host) } EXPORT_SYMBOL(mmc_power_restore_host); /* * Add barrier request to the requests in cache */ int mmc_cache_barrier(struct mmc_card *card) { struct mmc_host *host = card->host; int err = 0; if (!card->ext_csd.cache_ctrl || (card->quirks & MMC_QUIRK_CACHE_DISABLE)) goto out; if (!mmc_card_mmc(card)) goto out; if (!card->ext_csd.barrier_en) return -ENOTSUPP; /* * If a device receives maximum supported barrier * requests, a barrier command is treated as a * flush command. Hence, it is betetr to use * flush timeout instead a generic CMD6 timeout */ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_FLUSH_CACHE, 0x2, 0); if (err) pr_err("%s: cache barrier error %d\n", mmc_hostname(host), err); out: return err; } EXPORT_SYMBOL(mmc_cache_barrier); /* * Flush the cache to the non-volatile storage. */ Loading
drivers/mmc/core/mmc.c +31 −0 Original line number Diff line number Diff line Loading @@ -660,9 +660,19 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) mmc_hostname(card->host), card->ext_csd.cmdq_depth); } card->ext_csd.barrier_support = ext_csd[EXT_CSD_BARRIER_SUPPORT]; card->ext_csd.cache_flush_policy = ext_csd[EXT_CSD_CACHE_FLUSH_POLICY]; pr_info("%s: cache barrier support %d flush policy %d\n", mmc_hostname(card->host), card->ext_csd.barrier_support, card->ext_csd.cache_flush_policy); } else { card->ext_csd.cmdq_support = 0; card->ext_csd.cmdq_depth = 0; card->ext_csd.barrier_support = 0; card->ext_csd.cache_flush_policy = 0; } out: Loading Loading @@ -1848,6 +1858,27 @@ reinit: } else { card->ext_csd.cache_ctrl = 1; } /* enable cache barrier if supported by the device */ if (card->ext_csd.cache_ctrl && card->ext_csd.barrier_support) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BARRIER_CTRL, 1, card->ext_csd.generic_cmd6_time); if (err && err != -EBADMSG) { pr_err("%s: %s: mmc_switch() for BARRIER_CTRL fails %d\n", mmc_hostname(host), __func__, err); goto free_card; } if (err) { pr_warn("%s: Barrier is supported but failed to turn on (%d)\n", mmc_hostname(card->host), err); card->ext_csd.barrier_en = 0; err = 0; } else { card->ext_csd.barrier_en = 1; } } } else { /* * mmc standard doesn't say what is the card default Loading
include/linux/mmc/card.h +3 −0 Original line number Diff line number Diff line Loading @@ -116,10 +116,13 @@ struct mmc_ext_csd { u8 raw_pwr_cl_ddr_52_195; /* 238 */ u8 raw_pwr_cl_ddr_52_360; /* 239 */ u8 raw_pwr_cl_ddr_200_360; /* 253 */ u8 cache_flush_policy; /* 240 */ u8 raw_bkops_status; /* 246 */ u8 raw_sectors[4]; /* 212 - 4 bytes */ u8 cmdq_depth; /* 307 */ u8 cmdq_support; /* 308 */ u8 barrier_support; /* 486 */ u8 barrier_en; unsigned int feature_support; #define MMC_DISCARD_FEATURE BIT(0) /* CMD38 feature */ Loading
include/linux/mmc/core.h +1 −0 Original line number Diff line number Diff line Loading @@ -186,6 +186,7 @@ extern void mmc_put_card(struct mmc_card *card); extern void mmc_set_ios(struct mmc_host *host); extern int mmc_flush_cache(struct mmc_card *); extern int mmc_cache_barrier(struct mmc_card *); extern int mmc_detect_card_removed(struct mmc_host *host); Loading