If the IOMMU driver has a capable for merging segments to
a segment strictly, this can expose the host->mmc->max_segs with
multiple segments to a block layer by using blk_queue_max_segments()
that mmc_setup_queue() calls. Notes that an sdio card may be
possible to use multiple segments with non page aligned size, so
that this will not expose multiple segments to avoid failing
dma_map_sg() every time.

Notes that on renesas_sdhi_sys_dmac, the max_segs value will change
from 32 to 512, but the sys_dmac can handle 512 segments, so that
this init_card ops is added on "TMIO_MMC_MIN_RCAR2" environment.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda...@renesas.com>
---
 drivers/mmc/host/renesas_sdhi_core.c          | 27 +++++++++++++++++++++++++++
 drivers/mmc/host/renesas_sdhi_internal_dmac.c |  4 ++++
 2 files changed, 31 insertions(+)

diff --git a/drivers/mmc/host/renesas_sdhi_core.c 
b/drivers/mmc/host/renesas_sdhi_core.c
index c5ee4a6..379cefa 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -20,6 +20,7 @@
 
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <linux/iommu.h>
 #include <linux/kernel.h>
 #include <linux/mfd/tmio.h>
 #include <linux/mmc/host.h>
@@ -46,6 +47,8 @@
 #define SDHI_VER_GEN3_SD       0xcc10
 #define SDHI_VER_GEN3_SDMMC    0xcd10
 
+#define SDHI_MAX_SEGS_IN_IOMMU 512
+
 struct renesas_sdhi_quirks {
        bool hs400_disabled;
        bool hs400_4taps;
@@ -203,6 +206,28 @@ static void renesas_sdhi_clk_disable(struct tmio_mmc_host 
*host)
        clk_disable_unprepare(priv->clk_cd);
 }
 
+static void renesas_sdhi_init_card(struct mmc_host *mmc, struct mmc_card *card)
+{
+       struct tmio_mmc_host *host = mmc_priv(mmc);
+
+       /*
+        * If the IOMMU driver has a capable for merging segments to
+        * a segment strictly, this can expose the host->mmc->max_segs with
+        * multiple segments to a block layer by using blk_queue_max_segments()
+        * that mmc_setup_queue() calls. Notes that an sdio card may be
+        * possible to use multiple segments with non page aligned size, so
+        * that this will not expose multiple segments to avoid failing
+        * dma_map_sg() every time.
+        */
+       if (host->pdata->max_segs < SDHI_MAX_SEGS_IN_IOMMU &&
+           iommu_capable(host->pdev->dev.bus, IOMMU_CAP_MERGING) &&
+           (mmc_card_mmc(card) || mmc_card_sd(card)))
+               host->mmc->max_segs = SDHI_MAX_SEGS_IN_IOMMU;
+       else
+               host->mmc->max_segs = host->pdata->max_segs ? :
+                                     TMIO_DEFAULT_MAX_SEGS;
+}
+
 static int renesas_sdhi_card_busy(struct mmc_host *mmc)
 {
        struct tmio_mmc_host *host = mmc_priv(mmc);
@@ -726,6 +751,8 @@ int renesas_sdhi_probe(struct platform_device *pdev,
 
        /* SDR speeds are only available on Gen2+ */
        if (mmc_data->flags & TMIO_MMC_MIN_RCAR2) {
+               host->ops.init_card = renesas_sdhi_init_card;
+
                /* card_busy caused issues on r8a73a4 (pre-Gen2) CD-less SDHI */
                host->ops.card_busy = renesas_sdhi_card_busy;
                host->ops.start_signal_voltage_switch =
diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c 
b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
index 751fe91..a442f86 100644
--- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c
+++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c
@@ -11,6 +11,7 @@
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/io-64-nonatomic-hi-lo.h>
+#include <linux/iommu.h>
 #include <linux/mfd/tmio.h>
 #include <linux/mmc/host.h>
 #include <linux/mod_devicetable.h>
@@ -337,6 +338,9 @@ static int renesas_sdhi_internal_dmac_probe(struct 
platform_device *pdev)
        /* value is max of SD_SECCNT. Confirmed by HW engineers */
        dma_set_max_seg_size(dev, 0xffffffff);
 
+       if (iommu_capable(dev->bus, IOMMU_CAP_MERGING))
+               dma_set_iova_contiguous(dev, true);
+
        return renesas_sdhi_probe(pdev, &renesas_sdhi_internal_dmac_dma_ops);
 }
 
-- 
2.7.4

Reply via email to