Commit 69e7d76a authored by Yoshihiro Shimoda's avatar Yoshihiro Shimoda Committed by Ulf Hansson
Browse files

mmc: renesas_internal_dmac: add pre_req and post_req support



Add pre_req and post_req support to improve performance.

Inspired by a patch in the BSP by Masaharu Hayakawa.

Signed-off-by: default avatarYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Reviewed-by: default avatarWolfram Sang <wsa+renesas@sang-engineering.com>
Tested-by: default avatarWolfram Sang <wsa+renesas@sang-engineering.com>
Link: https://lore.kernel.org/r/1608114572-1892-3-git-send-email-yoshihiro.shimoda.uh@renesas.com


Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent d7aefb28
Loading
Loading
Loading
Loading
+83 −8
Original line number Diff line number Diff line
@@ -56,6 +56,12 @@
#define INFO2_DTRANERR1		BIT(17)
#define INFO2_DTRANERR0		BIT(16)

enum renesas_sdhi_dma_cookie {
	COOKIE_UNMAPPED,
	COOKIE_PRE_MAPPED,
	COOKIE_MAPPED,
};

/*
 * Specification of this driver:
 * - host->chan_{rx,tx} will be used as a flag of enabling/disabling the dma
@@ -172,6 +178,50 @@ renesas_sdhi_internal_dmac_dataend_dma(struct tmio_mmc_host *host) {
	tasklet_schedule(&priv->dma_priv.dma_complete);
}

/*
 * renesas_sdhi_internal_dmac_map() will be called with two difference
 * sg pointers in two mmc_data by .pre_req(), but tmio host can have a single
 * sg_ptr only. So, renesas_sdhi_internal_dmac_{un}map() should use a sg
 * pointer in a mmc_data instead of host->sg_ptr.
 */
static void
renesas_sdhi_internal_dmac_unmap(struct tmio_mmc_host *host,
				 struct mmc_data *data,
				 enum renesas_sdhi_dma_cookie cookie)
{
	bool unmap = cookie == COOKIE_UNMAPPED ? (data->host_cookie != cookie) :
						 (data->host_cookie == cookie);

	if (unmap) {
		dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
			     mmc_get_dma_dir(data));
		data->host_cookie = COOKIE_UNMAPPED;
	}
}

static bool
renesas_sdhi_internal_dmac_map(struct tmio_mmc_host *host,
			       struct mmc_data *data,
			       enum renesas_sdhi_dma_cookie cookie)
{
	if (data->host_cookie == COOKIE_PRE_MAPPED)
		return true;

	if (!dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
			    mmc_get_dma_dir(data)))
		return false;

	data->host_cookie = cookie;

	/* This DMAC cannot handle if buffer is not 128-bytes alignment */
	if (!IS_ALIGNED(sg_dma_address(data->sg), 128)) {
		renesas_sdhi_internal_dmac_unmap(host, data, cookie);
		return false;
	}

	return true;
}

static void
renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
				     struct mmc_data *data)
@@ -182,14 +232,9 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
	if (!test_bit(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY, &global_flags))
		dtran_mode |= DTRAN_MODE_ADDR_MODE;

	if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len,
			mmc_get_dma_dir(data)))
	if (!renesas_sdhi_internal_dmac_map(host, data, COOKIE_MAPPED))
		goto force_pio;

	/* This DMAC cannot handle if buffer is not 128-bytes alignment */
	if (!IS_ALIGNED(sg_dma_address(sg), 128))
		goto force_pio_with_unmap;

	if (data->flags & MMC_DATA_READ) {
		dtran_mode |= DTRAN_MODE_CH_NUM_CH1;
		if (test_bit(SDHI_INTERNAL_DMAC_ONE_RX_ONLY, &global_flags) &&
@@ -212,7 +257,7 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
	return;

force_pio_with_unmap:
	dma_unmap_sg(&host->pdev->dev, sg, host->sg_len, mmc_get_dma_dir(data));
	renesas_sdhi_internal_dmac_unmap(host, data, COOKIE_UNMAPPED);

force_pio:
	renesas_sdhi_internal_dmac_enable_dma(host, false);
@@ -245,7 +290,7 @@ static bool renesas_sdhi_internal_dmac_complete(struct tmio_mmc_host *host)
		dir = DMA_TO_DEVICE;

	renesas_sdhi_internal_dmac_enable_dma(host, false);
	dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->sg_len, dir);
	renesas_sdhi_internal_dmac_unmap(host, host->data, COOKIE_MAPPED);

	if (dir == DMA_FROM_DEVICE)
		clear_bit(SDHI_INTERNAL_DMAC_RX_IN_USE, &global_flags);
@@ -274,6 +319,32 @@ static void renesas_sdhi_internal_dmac_end_dma(struct tmio_mmc_host *host)
		renesas_sdhi_internal_dmac_complete(host);
}

static void renesas_sdhi_internal_dmac_post_req(struct mmc_host *mmc,
						struct mmc_request *mrq,
						int err)
{
	struct tmio_mmc_host *host = mmc_priv(mmc);
	struct mmc_data *data = mrq->data;

	if (!data)
		return;

	renesas_sdhi_internal_dmac_unmap(host, data, COOKIE_UNMAPPED);
}

static void renesas_sdhi_internal_dmac_pre_req(struct mmc_host *mmc,
					       struct mmc_request *mrq)
{
	struct tmio_mmc_host *host = mmc_priv(mmc);
	struct mmc_data *data = mrq->data;

	if (!data)
		return;

	data->host_cookie = COOKIE_UNMAPPED;
	renesas_sdhi_internal_dmac_map(host, data, COOKIE_PRE_MAPPED);
}

static void
renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host,
				       struct tmio_mmc_data *pdata)
@@ -295,6 +366,10 @@ renesas_sdhi_internal_dmac_request_dma(struct tmio_mmc_host *host,
	tasklet_init(&host->dma_issue,
		     renesas_sdhi_internal_dmac_issue_tasklet_fn,
		     (unsigned long)host);

	/* Add pre_req and post_req */
	host->ops.pre_req = renesas_sdhi_internal_dmac_pre_req;
	host->ops.post_req = renesas_sdhi_internal_dmac_post_req;
}

static void