aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorMike J. Chen <mjchen@google.com>2011-10-07 17:41:51 -0700
committerMike J. Chen <mjchen@google.com>2012-03-03 17:29:08 -0800
commit72d573bb78211d3dda9d8ab1dca5a3183c89b414 (patch)
tree7d36bd43f357e420abe61fc8c05c453d551c9f90 /drivers/mmc
parent14c2be93e06b710dd88d08a4937c44f008fea95f (diff)
downloaduboot-72d573bb78211d3dda9d8ab1dca5a3183c89b414.tar.gz
mmc: Change erase to do large contiguous blocks in one cmd
It's a lot faster when erasing many contiguous blocks to issue one command instead of doing it one erase group at a time because the MMC part can often do it in parallel. The issue it wasn't done earlier is timeouts. Specific to omap_hsmmc, make the erase code check for completion status after the erase command has been sent, and adjust the timeout used in that case to be relative to the number of blocks being erased. Other mmc drivers might need adjusting too to match this behavior and the ratio of timeout to number of blocks being erased is really device specific and not driver specific but for now we use a fixed ration of 1 second per 1000 blocks. Change-Id: I5e25c64d475ad8b5508926347e480ddcb7e5bb05 Signed-off-by: Mike J. Chen <mjchen@google.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/mmc.c17
-rw-r--r--drivers/mmc/omap_hsmmc.c33
2 files changed, 40 insertions, 10 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index fccde1f83..8bdb52f9b 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -319,19 +319,16 @@ mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt)
next += blk_r;
}
- /*
- * Now loop erasing erase_grp_size blocks each time. At first I tried
- * to do an erase for the whole thing at once, but timeouts ensued, so
- * I went back to the former approach.
- */
- while (blks_left > mmc->erase_grp_size) {
- err = mmc_erase_t(mmc, next, mmc->erase_grp_size);
+ /* Erase contiguouos blocks that are erase_grp_size aligned */
+ blk_r = (blks_left / mmc->erase_grp_size) * mmc->erase_grp_size;
+ if (blk_r) {
+ err = mmc_erase_t(mmc, next, blk_r);
printf("mmc_erase_t(), start %lu, blk_cnt %u, returned %d\n",
- next, mmc->erase_grp_size, err);
+ next, blk_r, err);
if (err)
goto exit;
- blks_left -= mmc->erase_grp_size;
- next += mmc->erase_grp_size;
+ blks_left -= blk_r;
+ next += blk_r;
}
/*
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index cc7ae98aa..4bc9f57ff 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -185,6 +185,9 @@ static int mmc_init_setup(struct mmc *mmc)
}
+static int last_start_value;
+static int last_end_value;
+
static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
{
@@ -207,6 +210,14 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
return TIMEOUT;
}
}
+
+ if ((cmd->cmdidx == SD_CMD_ERASE_WR_BLK_START) ||
+ (cmd->cmdidx == MMC_CMD_ERASE_GROUP_START))
+ last_start_value = cmd->cmdarg;
+ else if ((cmd->cmdidx == SD_CMD_ERASE_WR_BLK_END) ||
+ (cmd->cmdidx == MMC_CMD_ERASE_GROUP_END))
+ last_end_value = cmd->cmdarg;
+
/*
* CMDREG
* CMDIDX[13:8] : Command index
@@ -298,6 +309,28 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
mmc_write_data(mmc_base, data->src,
data->blocksize * data->blocks);
}
+
+ /* if this is an erase, wait for it to complete.
+ * Add additional time to the timeout based on number
+ * of blocks being erased. Add 1 second per
+ * 1000 blocks for now (1000 ms per 1 million blocks).
+ */
+ if (cmd->cmdidx == MMC_CMD_ERASE) {
+ ulong timeout_ms = MAX_RETRY_MS;
+ ulong erase_blk_cnt = last_end_value - last_start_value + 1;
+ timeout_ms += DIV_ROUND_UP(erase_blk_cnt, 1000);
+ printf("%s: erasing %lu blocks, timeout = %lu seconds\n",
+ __func__, erase_blk_cnt, timeout_ms / 1000);
+ start = get_timer(0);
+ while ((readl(&mmc_base->pstate) & DATI_MASK) == DATI_CMDDIS) {
+ if (get_timer(0) - start > timeout_ms) {
+ printf("%s: timedout waiting for cmddis"
+ " after command!\n", __func__);
+ return TIMEOUT;
+ }
+ }
+ }
+
return 0;
}