diff mbox series

[5/5] mmc: tmio: sdhi: Implement get_b_max function

Message ID 20200307164108.192532-5-marek.vasut+renesas@gmail.com
State Accepted
Commit 4a66d4ee336048b51bf5701a2abfac9a79c5a860
Headers show
Series [1/5] common: bouncebuf: Permit passing custom alignment check function | expand

Commit Message

Marek Vasut March 7, 2020, 4:41 p.m. UTC
Implement get_b_max() for the Renesas R-Car SDHI controller driver, limit
the b_max per hardware capabilities such that select Gen2 controllers have
16bit block transfer limit, the rest has 32bit block transfer limit and on
Gen3, the block transfer limit on addresses above the 32bit boundary is set
to 1/4 of the malloc area.

Originally, on Gen3, the block transfers above the 32bit area were limited
to PIO only, which resulted in (R8A7795 Salvator-X , HS200 eMMC):
  => time mmc read 0x0000000700000000 0 0x10000
  time: 0.151 seconds
  => time mmc read 0x0000000700000000 0 0x100000
  time: 11.090 seconds
with bounce buffer in place and b_max adjustment in place:
  => time mmc read 0x0000000700000000 0 0x10000
  time: 0.156 seconds
  => time mmc read 0x0000000700000000 0 0x100000
  time: 2.349 seconds

Note that the bounce buffer does mallocate and free the bounce buffer
for every transfer. Experiment which removes this results in further
increase of read speed, from 2.349s to 2.156s per 512 MiB of data,
which is not such a significant improvement anymore. It might however
be interesting to have bounce buffer directly in the MMC core or even
block core.

Signed-off-by: Marek Vasut <marek.vasut+renesas at gmail.com>
Cc: Daniel Schwierzeck <daniel.schwierzeck at gmail.com>
Cc: Masahiro Yamada <yamada.masahiro at socionext.com>
Cc: Peng Fan <peng.fan at nxp.com>
Cc: Simon Glass <sjg at chromium.org>
Cc: Tom Rini <trini at konsulko.com>
---
 drivers/mmc/renesas-sdhi.c | 46 +++++++++++++++++++++++++++++---------
 drivers/mmc/tmio-common.h  |  1 +
 2 files changed, 37 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
index 20c632c4af..9359fd3fe9 100644
--- a/drivers/mmc/renesas-sdhi.c
+++ b/drivers/mmc/renesas-sdhi.c
@@ -692,27 +692,25 @@  static int renesas_sdhi_wait_dat0(struct udevice *dev, int state,
 
 #define RENESAS_SDHI_DMA_ALIGNMENT	128
 
-static int renesas_sdhi_addr_aligned(struct bounce_buffer *state)
+static int renesas_sdhi_addr_aligned_gen(uintptr_t ubuf,
+					 size_t len, size_t len_aligned)
 {
-	uintptr_t ubuf = (uintptr_t)state->user_buffer;
-
 	/* Check if start is aligned */
 	if (!IS_ALIGNED(ubuf, RENESAS_SDHI_DMA_ALIGNMENT)) {
-		debug("Unaligned buffer address %p\n", state->user_buffer);
+		debug("Unaligned buffer address %zu\n", ubuf);
 		return 0;
 	}
 
 	/* Check if length is aligned */
-	if (state->len != state->len_aligned) {
-		debug("Unaligned buffer length %zu\n", state->len);
+	if (len != len_aligned) {
+		debug("Unaligned buffer length %zu\n", len);
 		return 0;
 	}
 
 	/* Check if below 32bit boundary */
-	if ((ubuf >> 32) || (ubuf + state->len_aligned) >> 32) {
-		debug("Buffer above 32bit boundary %p-%p\n",
-			state->user_buffer,
-			state->user_buffer + state->len_aligned);
+	if ((ubuf >> 32) || (ubuf + len_aligned) >> 32) {
+		debug("Buffer above 32bit boundary %lx-%lx\n",
+			ubuf, ubuf + len_aligned);
 		return 0;
 	}
 
@@ -720,6 +718,14 @@  static int renesas_sdhi_addr_aligned(struct bounce_buffer *state)
 	return 1;
 }
 
+static int renesas_sdhi_addr_aligned(struct bounce_buffer *state)
+{
+	uintptr_t ubuf = (uintptr_t)state->user_buffer;
+
+	return renesas_sdhi_addr_aligned_gen(ubuf, state->len,
+					     state->len_aligned);
+}
+
 static int renesas_sdhi_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
 				 struct mmc_data *data)
 {
@@ -787,6 +793,24 @@  static int renesas_sdhi_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
 	return 0;
 }
 
+int renesas_sdhi_get_b_max(struct udevice *dev, void *dst, lbaint_t blkcnt)
+{
+	struct tmio_sd_priv *priv = dev_get_priv(dev);
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	struct mmc *mmc = upriv->mmc;
+	size_t len = blkcnt * mmc->read_bl_len;
+	size_t len_align = roundup(len, RENESAS_SDHI_DMA_ALIGNMENT);
+
+	if (renesas_sdhi_addr_aligned_gen((uintptr_t)dst, len, len_align)) {
+		if (priv->quirks & TMIO_SD_CAP_16BIT)
+			return U16_MAX;
+		else
+			return U32_MAX;
+	} else {
+		return (CONFIG_SYS_MALLOC_LEN / 4) / mmc->read_bl_len;
+	}
+}
+
 static const struct dm_mmc_ops renesas_sdhi_ops = {
 	.send_cmd = renesas_sdhi_send_cmd,
 	.set_ios = renesas_sdhi_set_ios,
@@ -799,6 +823,7 @@  static const struct dm_mmc_ops renesas_sdhi_ops = {
 #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
 	.wait_dat0 = renesas_sdhi_wait_dat0,
 #endif
+	.get_b_max = renesas_sdhi_get_b_max,
 };
 
 #define RENESAS_GEN2_QUIRKS	TMIO_SD_CAP_RCAR_GEN2
@@ -964,6 +989,7 @@  static int renesas_sdhi_probe(struct udevice *dev)
 		return ret;
 	}
 
+	priv->quirks = quirks;
 	ret = tmio_sd_probe(dev, quirks);
 
 	renesas_sdhi_filter_caps(dev);
diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h
index 047458849b..2f671df4bc 100644
--- a/drivers/mmc/tmio-common.h
+++ b/drivers/mmc/tmio-common.h
@@ -147,6 +147,7 @@  struct tmio_sd_priv {
 	u8				adjust_hs400_calibrate;
 	u8				hs400_bad_tap;
 	const u8			*adjust_hs400_calib_table;
+	u32			quirks;
 #endif
 	ulong (*clk_get_rate)(struct tmio_sd_priv *);
 };