From 38c38cb73223218f6eedf485280917af1f8a0af2 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 28 Aug 2019 21:35:43 +0900 Subject: mmc: queue: use bigger segments if DMA MAP layer can merge the segments When the max_segs of a mmc host is smaller than 512, the mmc subsystem tries to use 512 segments if DMA MAP layer can merge the segments, and then the mmc subsystem exposes such information to the block layer by using blk_queue_can_use_dma_map_merging(). Signed-off-by: Yoshihiro Shimoda Reviewed-by: Ulf Hansson Reviewed-by: Simon Horman Signed-off-by: Christoph Hellwig --- drivers/mmc/core/queue.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 7102e2ebc614..1e29b305767e 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -21,6 +21,8 @@ #include "card.h" #include "host.h" +#define MMC_DMA_MAP_MERGE_SEGMENTS 512 + static inline bool mmc_cqe_dcmd_busy(struct mmc_queue *mq) { /* Allow only 1 DCMD at a time */ @@ -193,6 +195,12 @@ static void mmc_queue_setup_discard(struct request_queue *q, blk_queue_flag_set(QUEUE_FLAG_SECERASE, q); } +static unsigned int mmc_get_max_segments(struct mmc_host *host) +{ + return host->can_dma_map_merge ? MMC_DMA_MAP_MERGE_SEGMENTS : + host->max_segs; +} + /** * mmc_init_request() - initialize the MMC-specific per-request data * @q: the request queue @@ -206,7 +214,7 @@ static int __mmc_init_request(struct mmc_queue *mq, struct request *req, struct mmc_card *card = mq->card; struct mmc_host *host = card->host; - mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp); + mq_rq->sg = mmc_alloc_sg(mmc_get_max_segments(host), gfp); if (!mq_rq->sg) return -ENOMEM; @@ -362,13 +370,23 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card) blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_HIGH); blk_queue_max_hw_sectors(mq->queue, min(host->max_blk_count, host->max_req_size / 512)); - blk_queue_max_segments(mq->queue, host->max_segs); + if (host->can_dma_map_merge) + WARN(!blk_queue_can_use_dma_map_merging(mq->queue, + mmc_dev(host)), + "merging was advertised but not possible"); + blk_queue_max_segments(mq->queue, mmc_get_max_segments(host)); if (mmc_card_mmc(card)) block_size = card->ext_csd.data_sector_size; blk_queue_logical_block_size(mq->queue, block_size); - blk_queue_max_segment_size(mq->queue, + /* + * After blk_queue_can_use_dma_map_merging() was called with succeed, + * since it calls blk_queue_virt_boundary(), the mmc should not call + * both blk_queue_max_segment_size(). + */ + if (!host->can_dma_map_merge) + blk_queue_max_segment_size(mq->queue, round_down(host->max_seg_size, block_size)); dma_set_max_seg_size(mmc_dev(host), queue_max_segment_size(mq->queue)); @@ -418,6 +436,17 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card) mq->tag_set.cmd_size = sizeof(struct mmc_queue_req); mq->tag_set.driver_data = mq; + /* + * Since blk_mq_alloc_tag_set() calls .init_request() of mmc_mq_ops, + * the host->can_dma_map_merge should be set before to get max_segs + * from mmc_get_max_segments(). + */ + if (host->max_segs < MMC_DMA_MAP_MERGE_SEGMENTS && + dma_get_merge_boundary(mmc_dev(host))) + host->can_dma_map_merge = 1; + else + host->can_dma_map_merge = 0; + ret = blk_mq_alloc_tag_set(&mq->tag_set); if (ret) return ret; -- cgit v1.2.3-58-ga151 From 427b00342c5a3ebcf31fac2ce3b21fb993952816 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 12 Sep 2019 13:13:55 +0900 Subject: mmc: queue: Fix bigger segments usage The commit 38c38cb73223 ("mmc: queue: use bigger segments if DMA MAP layer can merge the segments") always enables the bugger segments if DMA MAP layer can merge the segments, but some controllers (SDHCI) have strictly limitation about the segments size, and then the commit breaks on the controllers. To fix the issue, this patch adds a new flag MMC_CAP2_MERGE_CAPABLE into the struct mmc_host and the bigger segments usage is disabled as default. Reported-by: Thierry Reding Fixes: 38c38cb73223 ("mmc: queue: use bigger segments if DMA MAP layer can merge the segments") Signed-off-by: Yoshihiro Shimoda Acked-by: Ulf Hansson Signed-off-by: Christoph Hellwig --- drivers/mmc/core/queue.c | 8 +++++++- include/linux/mmc/host.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index 1e29b305767e..9edc08685e86 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -399,6 +399,11 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card) init_waitqueue_head(&mq->wait); } +static inline bool mmc_merge_capable(struct mmc_host *host) +{ + return host->caps2 & MMC_CAP2_MERGE_CAPABLE; +} + /* Set queue depth to get a reasonable value for q->nr_requests */ #define MMC_QUEUE_DEPTH 64 @@ -441,7 +446,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card) * the host->can_dma_map_merge should be set before to get max_segs * from mmc_get_max_segments(). */ - if (host->max_segs < MMC_DMA_MAP_MERGE_SEGMENTS && + if (mmc_merge_capable(host) && + host->max_segs < MMC_DMA_MAP_MERGE_SEGMENTS && dma_get_merge_boundary(mmc_dev(host))) host->can_dma_map_merge = 1; else diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index c5662b3e64db..3becb28210f3 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -367,6 +367,7 @@ struct mmc_host { #define MMC_CAP2_CQE (1 << 23) /* Has eMMC command queue engine */ #define MMC_CAP2_CQE_DCMD (1 << 24) /* CQE can issue a direct command */ #define MMC_CAP2_AVOID_3_3V (1 << 25) /* Host must negotiate down from 3.3V */ +#define MMC_CAP2_MERGE_CAPABLE (1 << 26) /* Host can merge a segment over the segment size */ int fixed_drv_type; /* fixed driver type for non-removable media */ -- cgit v1.2.3-58-ga151 From c7d9eccb3c1e802c5cbb2a764eb0eb9807d9f12e Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Thu, 12 Sep 2019 13:13:56 +0900 Subject: mmc: renesas_sdhi_internal_dmac: Add MMC_CAP2_MERGE_CAPABLE Since this host controller can merge bigger segments if DMA API layer cam merge the segments, this patch adds the flag. Signed-off-by: Yoshihiro Shimoda Acked-by: Ulf Hansson Signed-off-by: Christoph Hellwig --- drivers/mmc/host/renesas_sdhi_internal_dmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 751fe91c7571..a66f8d6d61d1 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -106,7 +106,7 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, - .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT | MMC_CAP2_MERGE_CAPABLE, .bus_shift = 2, .scc_offset = 0x1000, .taps = rcar_gen3_scc_taps, -- cgit v1.2.3-58-ga151