linux-sunxi.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
From: Andre Przywara <andre.przywara@arm.com>
To: Jagan Teki <jagan@amarulasolutions.com>, Peng Fan <peng.fan@nxp.com>
Cc: u-boot@lists.denx.de, Jernej Skrabec <jernej.skrabec@gmail.com>,
	Samuel Holland <samuel@sholland.org>,
	Ondrej Jirman <megous@megous.com>,
	linux-sunxi@lists.linux.dev
Subject: [PATCH 7/8] mmc: sunxi: Increase MMIO FIFO read performance
Date: Tue, 25 May 2021 00:30:28 +0100	[thread overview]
Message-ID: <20210524233029.16417-8-andre.przywara@arm.com> (raw)
In-Reply-To: <20210524233029.16417-1-andre.przywara@arm.com>

To avoid the complexity of DMA operations (with chained descriptors), we
use repeated MMIO reads and writes to the SD_FIFO_REG, which allows us
to drain or fill the MMC data buffer FIFO very easily.

However those MMIO accesses are somewhat costly, so this limits our MMC
performance, to between 17 and 22 MB/s, but down to 9.5 MB/s on the H6
(partly due to the lower AHB1 frequency).

As it turns out we read the FIFO status register after *every* word we
read or write, which effectively doubles the number of MMIO accesses,
thus effectively more than halving our performance.

To avoid this overhead, we can make use of the FIFO level bits, which are
in the very same FIFO status registers.
So for a read request, we now can collect as many words as the FIFO
level originally indicated, and only then need to update the status
register.

We don't know for sure the size of the FIFO (and it seems to differ
across SoCs anyway), so writing is more fragile, which is why we still
use the old method for that. If we find a minimum FIFO size available on
all SoCs, we could use that, in a later optimisation.

This patch increases the eMMC read speed on a Pine64-LTS from about
22MB/s to 44 MB/s. SD card reads don't gain that much, but with 23 MB/s
we now reach the practical limit for 3.3V SD cards.
On the H6 we double our transfer speed, from 9.5 MB/s to 19.7 MB/s.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arch/arm/include/asm/arch-sunxi/mmc.h |  1 +
 drivers/mmc/sunxi_mmc.c               | 39 +++++++++++++++++++++------
 2 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/arch/arm/include/asm/arch-sunxi/mmc.h b/arch/arm/include/asm/arch-sunxi/mmc.h
index 340e25b04d2..5daacf10eb1 100644
--- a/arch/arm/include/asm/arch-sunxi/mmc.h
+++ b/arch/arm/include/asm/arch-sunxi/mmc.h
@@ -119,6 +119,7 @@ struct sunxi_mmc {
 #define SUNXI_MMC_STATUS_CARD_PRESENT		(0x1 << 8)
 #define SUNXI_MMC_STATUS_CARD_DATA_BUSY		(0x1 << 9)
 #define SUNXI_MMC_STATUS_DATA_FSM_BUSY		(0x1 << 10)
+#define SUNXI_MMC_STATUS_FIFO_LEVEL(reg)	(((reg) >> 17) & 0x3fff)
 
 #define SUNXI_MMC_NTSR_MODE_SEL_NEW		(0x1 << 31)
 
diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index a30fd8fbdb1..115b519546e 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -311,8 +311,9 @@ static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
 					      SUNXI_MMC_STATUS_FIFO_FULL;
 	unsigned i;
 	unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
-	unsigned byte_cnt = data->blocksize * data->blocks;
-	unsigned timeout_msecs = byte_cnt >> 8;
+	unsigned word_cnt = (data->blocksize * data->blocks) >> 2;
+	unsigned timeout_msecs = word_cnt >> 6;
+	uint32_t status;
 	unsigned long  start;
 
 	if (timeout_msecs < 2000)
@@ -323,16 +324,38 @@ static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
 
 	start = get_timer(0);
 
-	for (i = 0; i < (byte_cnt >> 2); i++) {
-		while (readl(&priv->reg->status) & status_bit) {
+	for (i = 0; i < word_cnt;) {
+		unsigned int in_fifo;
+
+		while ((status = readl(&priv->reg->status)) & status_bit) {
 			if (get_timer(start) > timeout_msecs)
 				return -1;
 		}
 
-		if (reading)
-			buff[i] = readl(&priv->reg->fifo);
-		else
-			writel(buff[i], &priv->reg->fifo);
+		/*
+		 * For writing we do not easily know the FIFO size, so have
+		 * to check the FIFO status after every word written.
+		 * TODO: For optimisation we could work out a minimum FIFO
+		 * size across all SoCs, and use that together with the current
+		 * fill level to write chunks of words.
+		 */
+		if (!reading) {
+			writel(buff[i++], &priv->reg->fifo);
+			continue;
+		}
+
+		/*
+		 * The status register holds the current FIFO level, so we
+		 * can be sure to collect as many words from the FIFO
+		 * register without checking the status register after every
+		 * read. That saves half of the costly MMIO reads, effectively
+		 * doubling the read performance.
+		 */
+		for (in_fifo = SUNXI_MMC_STATUS_FIFO_LEVEL(status);
+		     in_fifo > 0;
+		     in_fifo--)
+			buff[i++] = readl_relaxed(&priv->reg->fifo);
+		dmb();
 	}
 
 	return 0;
-- 
2.17.5


  parent reply	other threads:[~2021-05-24 23:31 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-24 23:30 [PATCH 0/8] sunxi: mmc: Fixes and speed increase Andre Przywara
2021-05-24 23:30 ` [PATCH 1/8] mmc: sunxi: Avoid #ifdefs in delay and width setup Andre Przywara
2021-05-25  1:42   ` Jaehoon Chung
2021-05-24 23:30 ` [PATCH 2/8] mmc: sunxi: Fix warnings with CONFIG_PHYS_64BIT Andre Przywara
2021-05-25  1:43   ` Jaehoon Chung
2021-05-24 23:30 ` [PATCH 3/8] mmc: sunxi: Fix MMC clock parent selection Andre Przywara
2021-05-24 23:30 ` [PATCH 4/8] mmc: sunxi: Cleanup "new timing mode" selection Andre Przywara
2021-05-25  1:43   ` Jaehoon Chung
2021-05-24 23:30 ` [PATCH 5/8] mmc: sunxi: Enable "new timing mode" on all new SoCs Andre Przywara
2021-05-24 23:30 ` [PATCH 6/8] mmc: sunxi: Cleanup and fix self-calibration code Andre Przywara
2021-05-24 23:30 ` Andre Przywara [this message]
2021-05-24 23:30 ` [PATCH 8/8] mmc: sunxi: Use mmc_of_parse() Andre Przywara
2021-05-25  1:43   ` Jaehoon Chung
2021-07-03 23:24 ` [PATCH 0/8] sunxi: mmc: Fixes and speed increase Andre Przywara
2021-07-04 19:56   ` Samuel Holland

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210524233029.16417-8-andre.przywara@arm.com \
    --to=andre.przywara@arm.com \
    --cc=jagan@amarulasolutions.com \
    --cc=jernej.skrabec@gmail.com \
    --cc=linux-sunxi@lists.linux.dev \
    --cc=megous@megous.com \
    --cc=peng.fan@nxp.com \
    --cc=samuel@sholland.org \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).