All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit 642c28ab authored by David Jander's avatar David Jander Committed by Ulf Hansson

mmc: core: Optimize case for exactly one erase-group budget

In the (not so unlikely) case that the mmc controller timeout budget is
enough for exactly one erase-group, the simplification of allowing one
sector has an enormous performance penalty. We optimize this special case
by introducing a flag that prohibits erase-group boundary crossing, so
that we can allow trimming more than one sector at a time.
Signed-off-by: default avatarDavid Jander <>
Signed-off-by: default avatarUlf Hansson <>
parent 2c6625cd
......@@ -2168,6 +2168,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
unsigned int arg)
unsigned int rem, to = from + nr;
int err;
if (!(card->host->caps & MMC_CAP_ERASE) ||
!(card->csd.cmdclass & CCC_ERASE))
......@@ -2218,6 +2219,23 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
/* 'from' and 'to' are inclusive */
to -= 1;
* Special case where only one erase-group fits in the timeout budget:
* If the region crosses an erase-group boundary on this particular
* case, we will be trimming more than one erase-group which, does not
* fit in the timeout budget of the controller, so we need to split it
* and call mmc_do_erase() twice if necessary. This special case is
* identified by the card->eg_boundary flag.
if ((arg & MMC_TRIM_ARGS) && (card->eg_boundary) &&
(from % card->erase_size)) {
rem = card->erase_size - (from % card->erase_size);
err = mmc_do_erase(card, from, from + rem - 1, arg);
from += rem;
if ((err) || (to <= from))
return err;
return mmc_do_erase(card, from, to, arg);
......@@ -2313,16 +2331,28 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
if (!qty)
return 0;
* When specifying a sector range to trim, chances are we might cross
* an erase-group boundary even if the amount of sectors is less than
* one erase-group.
* If we can only fit one erase-group in the controller timeout budget,
* we have to care that erase-group boundaries are not crossed by a
* single trim operation. We flag that special case with "eg_boundary".
* In all other cases we can just decrement qty and pretend that we
* always touch (qty + 1) erase-groups as a simple optimization.
if (qty == 1)
return 1;
card->eg_boundary = 1;
/* Convert qty to sectors */
if (card->erase_shift)
max_discard = --qty << card->erase_shift;
max_discard = qty << card->erase_shift;
else if (mmc_card_sd(card))
max_discard = qty;
max_discard = qty + 1;
max_discard = --qty * card->erase_size;
max_discard = qty * card->erase_size;
return max_discard;
......@@ -283,6 +283,7 @@ struct mmc_card {
unsigned int erase_size; /* erase size in sectors */
unsigned int erase_shift; /* if erase unit is power 2 */
unsigned int pref_erase; /* in sectors */
unsigned int eg_boundary; /* don't cross erase-group boundaries */
u8 erased_byte; /* value of erased bytes */
u32 raw_cid[4]; /* raw card CID */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment