[U-Boot] [PATCH 3/4] MMC Multi-block Support

Added Multi-Block Read support for Generic MMC. Modified existing multi-block write to limit the maximum number of blocks per transfer. This feature is enabled with CONFIG_MMC_MBLOCK option. A new member is added in the mmc structure for the host controller to specify the maximum number of blocks it supports.
Signed-off-by: Alagu Sankar alagusankar@embwise.com --- drivers/mmc/mmc.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/mmc.h | 3 + 2 files changed, 159 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e7abf94..3f5a200 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -77,6 +77,7 @@ struct mmc *find_mmc_device(int dev_num) return NULL; }
+#ifndef CONFIG_MMC_MBLOCK static ulong mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src) { @@ -238,6 +239,156 @@ static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst) return blkcnt; }
+#else + +static int mmc_write_blocks(struct mmc *mmc, const char *src, uint start, + uint blkcnt) +{ + struct mmc_cmd cmd; + struct mmc_data data; + int err; + int blklen; + + blklen = mmc->write_bl_len; + + err = mmc_set_blocklen(mmc, mmc->write_bl_len); + + if (err) { + printf("set write bl len failed\n\r"); + return err; + } + + if (blkcnt > 1) + cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; + else + cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK; + + if (mmc->high_capacity) + cmd.cmdarg = start; + else + cmd.cmdarg = start * blklen; + + cmd.resp_type = MMC_RSP_R1; + cmd.flags = 0; + + data.src = src; + data.blocks = blkcnt; + data.blocksize = blklen; + data.flags = MMC_DATA_WRITE; + + err = mmc_send_cmd(mmc, &cmd, &data); + + if (err) { + printf("mmc write failed\n\r"); + return err; + } + + if (blkcnt > 1) { + cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; + cmd.cmdarg = 0; + cmd.resp_type = MMC_RSP_R1b; + cmd.flags = 0; + err = mmc_send_cmd(mmc, &cmd, NULL); + } + + return err; +} + +static ulong +mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void *src) +{ + int err; + int i; + struct mmc *mmc = find_mmc_device(dev_num); + uint b_max = mmc->b_max; + + if (!mmc) + return 0; + + for (i = blkcnt; i > 0; i -= b_max) { + uint blocks = (i > b_max) ? b_max : i; + + err = mmc_write_blocks(mmc, src, start, blocks); + if (err) + return blkcnt - i; + start += blocks; + src += (mmc->write_bl_len * blocks); + } + + return blkcnt; +} + +int mmc_read_blocks(struct mmc *mmc, void *dst, uint blocknum, uint blkcnt) +{ + int err; + struct mmc_cmd cmd; + struct mmc_data data; + + if (blkcnt > 1) + cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; + else + cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; + + if (mmc->high_capacity) + cmd.cmdarg = blocknum; + else + cmd.cmdarg = blocknum * mmc->read_bl_len; + + cmd.resp_type = MMC_RSP_R1; + cmd.flags = 0; + + data.dest = dst; + data.blocks = blkcnt; + data.blocksize = mmc->read_bl_len; + data.flags = MMC_DATA_READ; + + err = mmc_send_cmd(mmc, &cmd, &data); + if (err) + return err; + + if (blkcnt > 1) { + cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; + cmd.cmdarg = 0; + cmd.resp_type = MMC_RSP_R1b; + cmd.flags = 0; + err = mmc_send_cmd(mmc, &cmd, NULL); + } + + return err; +} + +static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst) +{ + int err; + int i; + struct mmc *mmc = find_mmc_device(dev_num); + uint b_max = mmc->b_max; + + if (!mmc) + return 0; + + /* We always do full block reads from the card */ + err = mmc_set_blocklen(mmc, mmc->read_bl_len); + if (err) + return 0; + + for (i = blkcnt; i > 0; i -= b_max) { + uint blocks = (i > b_max) ? b_max : i; + + err = mmc_read_blocks(mmc, dst, start, blocks); + if (err) { + printf("block read failed: %d\n", err); + return blkcnt - i; + } + start += blocks; + dst += (mmc->read_bl_len * blocks); + } + + return blkcnt; +} + +#endif + int mmc_go_idle(struct mmc* mmc) { struct mmc_cmd cmd; @@ -858,6 +1009,11 @@ int mmc_register(struct mmc *mmc) mmc->block_dev.block_read = mmc_bread; mmc->block_dev.block_write = mmc_bwrite;
+#ifdef CONFIG_MMC_MBLOCK + if (mmc->b_max == 0) + mmc->b_max = 1; +#endif + INIT_LIST_HEAD (&mmc->link);
list_add_tail (&mmc->link, &mmc_devices); diff --git a/include/mmc.h b/include/mmc.h index 8973bc7..04c7eaf 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -264,6 +264,9 @@ struct mmc { struct mmc_cmd *cmd, struct mmc_data *data); void (*set_ios)(struct mmc *mmc); int (*init)(struct mmc *mmc); +#ifdef CONFIG_MMC_MBLOCK + uint b_max; +#endif };
int mmc_register(struct mmc *mmc);

Hi,
Personally I think this patch can be used as common. CONFIG_MMC_MBLOCK is not needed. It can improve performance a lot for generic mmc.
Thanks~~
Yours Terry
-----Original Message----- From: u-boot-bounces@lists.denx.de [mailto:u-boot-bounces@lists.denx.de] On Behalf Of Alagu Sankar Sent: 2010年5月12日 17:43 To: u-boot@lists.denx.de Subject: [U-Boot] [PATCH 3/4] MMC Multi-block Support
Added Multi-Block Read support for Generic MMC. Modified existing multi-block write to limit the maximum number of blocks per transfer. This feature is enabled with CONFIG_MMC_MBLOCK option. A new member is added in the mmc structure for the host controller to specify the maximum number of blocks it supports.
Signed-off-by: Alagu Sankar alagusankar@embwise.com
drivers/mmc/mmc.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/mmc.h | 3 + 2 files changed, 159 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e7abf94..3f5a200 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -77,6 +77,7 @@ struct mmc *find_mmc_device(int dev_num) return NULL; }
+#ifndef CONFIG_MMC_MBLOCK static ulong mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src) { @@ -238,6 +239,156 @@ static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst) return blkcnt; }
+#else
+static int mmc_write_blocks(struct mmc *mmc, const char *src, uint start,
uint blkcnt)
+{
- struct mmc_cmd cmd;
- struct mmc_data data;
- int err;
- int blklen;
- blklen = mmc->write_bl_len;
- err = mmc_set_blocklen(mmc, mmc->write_bl_len);
- if (err) {
printf("set write bl len failed\n\r");
return err;
- }
- if (blkcnt > 1)
cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
- else
cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
- if (mmc->high_capacity)
cmd.cmdarg = start;
- else
cmd.cmdarg = start * blklen;
- cmd.resp_type = MMC_RSP_R1;
- cmd.flags = 0;
- data.src = src;
- data.blocks = blkcnt;
- data.blocksize = blklen;
- data.flags = MMC_DATA_WRITE;
- err = mmc_send_cmd(mmc, &cmd, &data);
- if (err) {
printf("mmc write failed\n\r");
return err;
- }
- if (blkcnt > 1) {
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
- }
- return err;
+}
+static ulong +mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void *src) +{
- int err;
- int i;
- struct mmc *mmc = find_mmc_device(dev_num);
- uint b_max = mmc->b_max;
- if (!mmc)
return 0;
- for (i = blkcnt; i > 0; i -= b_max) {
uint blocks = (i > b_max) ? b_max : i;
err = mmc_write_blocks(mmc, src, start, blocks);
if (err)
return blkcnt - i;
start += blocks;
src += (mmc->write_bl_len * blocks);
- }
- return blkcnt;
+}
+int mmc_read_blocks(struct mmc *mmc, void *dst, uint blocknum, uint +blkcnt) {
- int err;
- struct mmc_cmd cmd;
- struct mmc_data data;
- if (blkcnt > 1)
cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
- else
cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
- if (mmc->high_capacity)
cmd.cmdarg = blocknum;
- else
cmd.cmdarg = blocknum * mmc->read_bl_len;
- cmd.resp_type = MMC_RSP_R1;
- cmd.flags = 0;
- data.dest = dst;
- data.blocks = blkcnt;
- data.blocksize = mmc->read_bl_len;
- data.flags = MMC_DATA_READ;
- err = mmc_send_cmd(mmc, &cmd, &data);
- if (err)
return err;
- if (blkcnt > 1) {
cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
cmd.flags = 0;
err = mmc_send_cmd(mmc, &cmd, NULL);
- }
- return err;
+}
+static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void +*dst) {
- int err;
- int i;
- struct mmc *mmc = find_mmc_device(dev_num);
- uint b_max = mmc->b_max;
- if (!mmc)
return 0;
- /* We always do full block reads from the card */
- err = mmc_set_blocklen(mmc, mmc->read_bl_len);
- if (err)
return 0;
- for (i = blkcnt; i > 0; i -= b_max) {
uint blocks = (i > b_max) ? b_max : i;
err = mmc_read_blocks(mmc, dst, start, blocks);
if (err) {
printf("block read failed: %d\n", err);
return blkcnt - i;
}
start += blocks;
dst += (mmc->read_bl_len * blocks);
- }
- return blkcnt;
+}
+#endif
int mmc_go_idle(struct mmc* mmc) { struct mmc_cmd cmd; @@ -858,6 +1009,11 @@ int mmc_register(struct mmc *mmc) mmc->block_dev.block_read = mmc_bread; mmc->block_dev.block_write = mmc_bwrite;
+#ifdef CONFIG_MMC_MBLOCK
- if (mmc->b_max == 0)
mmc->b_max = 1;
+#endif
INIT_LIST_HEAD (&mmc->link);
list_add_tail (&mmc->link, &mmc_devices); diff --git
a/include/mmc.h b/include/mmc.h index 8973bc7..04c7eaf 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -264,6 +264,9 @@ struct mmc { struct mmc_cmd *cmd, struct mmc_data *data); void (*set_ios)(struct mmc *mmc); int (*init)(struct mmc *mmc); +#ifdef CONFIG_MMC_MBLOCK
- uint b_max;
+#endif };
int mmc_register(struct mmc *mmc);
1.6.0.6
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
participants (2)
-
Alagu Sankar
-
Lv Terry-R65388