If max_segs of a mmc host is smaller than BLK_MAX_SEGMENTS,
the mmc subsystem tries to use such bigger segments by using
IOMMU subsystem, and then the mmc subsystem exposes such information
to the block layer by using blk_queue_can_use_iommu_merging().

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda...@renesas.com>
---
 drivers/mmc/core/queue.c | 33 +++++++++++++++++++++++++++++----
 include/linux/mmc/host.h |  1 +
 2 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c
index b5b9c61..59d7606 100644
--- a/drivers/mmc/core/queue.c
+++ b/drivers/mmc/core/queue.c
@@ -196,6 +196,11 @@ 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_merge ? BLK_MAX_SEGMENTS : host->max_segs;
+}
+
 /**
  * mmc_init_request() - initialize the MMC-specific per-request data
  * @q: the request queue
@@ -209,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;
 
@@ -368,15 +373,24 @@ static void mmc_setup_queue(struct mmc_queue *mq, struct 
mmc_card *card)
        blk_queue_bounce_limit(mq->queue, limit);
        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);
+       /* blk_queue_can_use_iommu_merging() should succeed if can_merge = 1 */
+       if (host->can_merge &&
+           !blk_queue_can_use_iommu_merging(mq->queue, mmc_dev(host)))
+               WARN_ON(1);
+       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_iommu_merging() was called with succeed,
+        * since it calls blk_queue_virt_boundary for IOMMU, the mmc should
+        * not call blk_queue_max_segment_size().
+        */
+       if (!host->can_merge)
+               blk_queue_max_segment_size(mq->queue,
                        round_down(host->max_seg_size, block_size));
-
        INIT_WORK(&mq->recovery_work, mmc_mq_recovery_handler);
        INIT_WORK(&mq->complete_work, mmc_blk_mq_complete_work);
 
@@ -422,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_merge should be set before to get max_segs from
+        * mmc_get_max_segments().
+        */
+       if (host->max_segs < BLK_MAX_SEGMENTS &&
+           device_iommu_mapped(mmc_dev(host)))
+               host->can_merge = 1;
+       else
+               host->can_merge = 0;
+
        ret = blk_mq_alloc_tag_set(&mq->tag_set);
        if (ret)
                return ret;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 43d0f0c..84b9bef 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -398,6 +398,7 @@ struct mmc_host {
        unsigned int            retune_now:1;   /* do re-tuning at next req */
        unsigned int            retune_paused:1; /* re-tuning is temporarily 
disabled */
        unsigned int            use_blk_mq:1;   /* use blk-mq */
+       unsigned int            can_merge:1;    /* merging can be used */
 
        int                     rescan_disable; /* disable card detection */
        int                     rescan_entered; /* used with nonremovable 
devices */
-- 
2.7.4

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to