From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH 1/2] mci: core: import Linux logic for higher preferred erase size
Date: Fri, 14 Feb 2025 10:48:49 +0100 [thread overview]
Message-ID: <20250214094850.2847143-1-a.fatoum@pengutronix.de> (raw)
As a comment in the file notes, doing too small a granularity for erases
has considerable effect on performance:
> Example Samsung eMMC 8GTF4:
>
> time erase /dev/mmc2.part_of_512m # 1024 trims
> time: 2849ms
>
> time erase /dev/mmc2.part_of_512m # single trim
> time: 56ms
This was deemed acceptable at first, because 3 seconds is still
tolerable.
On a SkyHigh S40004, an erase of the whole 3728 MiB ended up
taking longer than 400s in barebox, but only 4s in Linux, which
dwarfs the time actually needed for writing.
Linux has some rather complicated logic to compute a higher erase size
granularity, which still fits in the max busy timeout that a controller
may require. Until that's support in barebox, we import a simpler
heuristic that Linux uses to compute
/sys/class/mmc_host/*/*/preferred_erase_size
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/mci/mci-core.c | 105 ++++++++++++++++++++++++++---------------
include/mci.h | 1 +
2 files changed, 69 insertions(+), 37 deletions(-)
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index cc3c6fba3653..6d55eb8305b9 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1774,6 +1774,70 @@ static int mci_startup_mmc(struct mci *mci)
return ret >= MMC_BUS_WIDTH_1 ? 0 : ret;
}
+static void mci_init_erase(struct mci *card)
+{
+ unsigned int sz;
+
+ if (!IS_ENABLED(CONFIG_MCI_ERASE))
+ return;
+
+ /* TODO: While it's possible to clear many erase groups at once
+ * and it greatly improves throughput, drivers need adjustment:
+ *
+ * Many drivers hardcode a maximal wait time before aborting
+ * the wait for R1b and returning -ETIMEDOUT. With long
+ * erases/trims, we are bound to run into this timeout, so for now
+ * we just split into sufficiently small erases that are unlikely
+ * to trigger the timeout.
+ *
+ * What Linux does and what we should be doing in barebox is:
+ *
+ * - add a struct mci_cmd::busy_timeout member that drivers should
+ * use instead of hardcoding their own timeout delay. The busy
+ * timeout length can be calculated by the MCI core after
+ * consulting the appropriate CSD/EXT_CSD/SSR registers.
+ *
+ * - add a struct mci_host::max_busy_timeout member, where drivers
+ * can indicate the maximum timeout they are able to support.
+ * The MCI core will never set a busy_timeout that exceeds this
+ * value.
+ *
+ * Example Samsung eMMC 8GTF4:
+ *
+ * time erase /dev/mmc2.part_of_512m # 1024 trims
+ * time: 2849ms
+ *
+ * time erase /dev/mmc2.part_of_512m # single trim
+ * time: 56ms
+ */
+ if (IS_SD(card) && card->ssr.au) {
+ card->pref_erase = card->ssr.au;
+ } else if (card->erase_grp_size) {
+ sz = card->capacity >> 11;
+ if (sz < 128)
+ card->pref_erase = 512 * 1024 / 512;
+ else if (sz < 512)
+ card->pref_erase = 1024 * 1024 / 512;
+ else if (sz < 1024)
+ card->pref_erase = 2 * 1024 * 1024 / 512;
+ else
+ card->pref_erase = 4 * 1024 * 1024 / 512;
+ if (card->pref_erase < card->erase_grp_size)
+ card->pref_erase = card->erase_grp_size;
+ else {
+ sz = card->pref_erase % card->erase_grp_size;
+ if (sz)
+ card->pref_erase += card->erase_grp_size - sz;
+ }
+ } else {
+ card->pref_erase = 0;
+ return;
+ }
+
+ dev_add_param_uint32_fixed(&card->dev, "preferred_erase_size",
+ card->pref_erase * 512, "%u");
+}
+
/**
* Scan the given host interfaces and detect connected MMC/SD cards
* @param mci MCI instance
@@ -1903,6 +1967,8 @@ static int mci_startup(struct mci *mci)
/* we setup the blocklength only one times for all accesses to this media */
err = mci_set_blocklen(mci, mci->read_bl_len);
+ mci_init_erase(mci);
+
mci_part_add(mci, mci->capacity, 0,
mci->cdevname, NULL, 0, true,
MMC_BLK_DATA_AREA_MAIN);
@@ -2080,7 +2146,7 @@ static int mci_sd_erase(struct block_device *blk, sector_t from,
struct mci *mci = part->mci;
sector_t i = 0;
unsigned arg;
- sector_t blk_max, to = from + blkcnt;
+ sector_t to = from + blkcnt;
int rc;
mci_blk_part_switch(part);
@@ -2106,45 +2172,10 @@ static int mci_sd_erase(struct block_device *blk, sector_t from,
/* 'from' and 'to' are inclusive */
to -= 1;
- /* TODO: While it's possible to clear many erase groups at once
- * and it greatly improves throughput, drivers need adjustment:
- *
- * Many drivers hardcode a maximal wait time before aborting
- * the wait for R1b and returning -ETIMEDOUT. With long
- * erases/trims, we are bound to run into this timeout, so for now
- * we just split into sufficiently small erases that are unlikely
- * to trigger the timeout.
- *
- * What Linux does and what we should be doing in barebox is:
- *
- * - add a struct mci_cmd::busy_timeout member that drivers should
- * use instead of hardcoding their own timeout delay. The busy
- * timeout length can be calculated by the MCI core after
- * consulting the appropriate CSD/EXT_CSD/SSR registers.
- *
- * - add a struct mci_host::max_busy_timeout member, where drivers
- * can indicate the maximum timeout they are able to support.
- * The MCI core will never set a busy_timeout that exceeds this
- * value.
- *
- * Example Samsung eMMC 8GTF4:
- *
- * time erase /dev/mmc2.part_of_512m # 1024 trims
- * time: 2849ms
- *
- * time erase /dev/mmc2.part_of_512m # single trim
- * time: 56ms
- */
-
- if (IS_SD(mci) && mci->ssr.au)
- blk_max = mci->ssr.au;
- else
- blk_max = mci->erase_grp_size;
-
while (i < blkcnt) {
sector_t blk_r;
- blk_r = min(blkcnt - i, blk_max);
+ blk_r = min_t(blkcnt_t, blkcnt - i, mci->pref_erase);
rc = mci_block_erase(mci, from + i, blk_r, arg);
if (rc)
diff --git a/include/mci.h b/include/mci.h
index 1e3757027406..15fc0f22088f 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -647,6 +647,7 @@ struct mci {
/** currently used data block length for write accesses */
unsigned write_bl_len;
unsigned erase_grp_size;
+ unsigned pref_erase; /**< preferred erase granularity in blocks */
uint64_t capacity; /**< Card's data capacity in bytes */
int ready_for_use; /** true if already probed */
int dsr_imp; /**< DSR implementation state from CSD */
--
2.39.5
next reply other threads:[~2025-02-14 9:59 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-14 9:48 Ahmad Fatoum [this message]
2025-02-14 9:48 ` [PATCH 2/2] mci: core: reset ERASE_GRP_DEF on startup Ahmad Fatoum
2025-02-17 10:53 ` [PATCH 1/2] mci: core: import Linux logic for higher preferred erase size Sascha Hauer
2025-02-17 11:36 ` Ahmad Fatoum
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=20250214094850.2847143-1-a.fatoum@pengutronix.de \
--to=a.fatoum@pengutronix.de \
--cc=barebox@lists.infradead.org \
/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