On Fri, Aug 25, 2006 at 05:10:56PM -0700, Jeff Hane wrote:
> On Fri, 2006-08-25 at 15:04 -0700, David Brownell wrote:
> > On Friday 25 August 2006 1:24 pm, Jeff Hane wrote:
> >
> > > So am curious to know why multiblock writes are not enable.
> >
> > ISTR because one of the early MMC implementations, for pxa250,
> > has execrable fault reporting which prevents reporting how
> > many blocks were actually transferred after a fault.
> >
> > You didn't say what platform you're using, but I thought some
> > of them _do_ support multiblock writes.
>
> It's an in-house board using a at91rm2000. However, the current code
> that restricts multiblock writes is in mmc_block.c which is common to
> all platforms. Thats why I wanted to know if anybody has made changes
> to make it work for their board and if there were any negative side-
> effects.
You might find this patch interesting. However, you must only ever
set MMC_CAP_MULTI_WRITE if your host driver returns the number of
bytes successfully transferred to the card prior to a bus error
occuring during the data phase.
Failure to observe that restriction will result in data corruption
on bus errors.
Signed-off-by: Russell King <rmk+kernel@xxxxxxxxxxxxxxxx>
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index bc69c0b..b375536 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -31,6 +31,7 @@ #include <linux/mutex.h>
#include <linux/mmc/card.h>
#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -164,6 +165,7 @@ static int mmc_blk_issue_rq(struct mmc_q
do {
struct mmc_blk_request brq;
struct mmc_command cmd;
+ u32 readcmd, writecmd;
memset(&brq, 0, sizeof(struct mmc_blk_request));
brq.mrq.cmd = &brq.cmd;
@@ -179,13 +181,31 @@ static int mmc_blk_issue_rq(struct mmc_q
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ /*
+ * If the host doesn't support multiple block writes, force
+ * block writes to single block.
+ */
+ if (rq_data_dir(req) != READ &&
+ !(card->host->caps & MMC_CAP_MULTI_WRITE))
+ brq.data.blocks = 1;
+
+ if (brq.data.blocks > 1) {
+ brq.data.flags |= MMC_DATA_MULTI;
+ brq.mrq.stop = &brq.stop;
+ readcmd = MMC_READ_MULTIPLE_BLOCK;
+ writecmd = MMC_WRITE_MULTIPLE_BLOCK;
+ } else {
+ brq.mrq.stop = NULL;
+ readcmd = MMC_READ_SINGLE_BLOCK;
+ writecmd = MMC_WRITE_BLOCK;
+ }
+
if (rq_data_dir(req) == READ) {
- brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
+ brq.cmd.opcode = readcmd;
brq.data.flags |= MMC_DATA_READ;
} else {
- brq.cmd.opcode = MMC_WRITE_BLOCK;
+ brq.cmd.opcode = writecmd;
brq.data.flags |= MMC_DATA_WRITE;
- brq.data.blocks = 1;
/*
* Scale up the timeout by the r2w factor
@@ -194,13 +214,6 @@ static int mmc_blk_issue_rq(struct mmc_q
brq.data.timeout_clks <<= card->csd.r2w_factor;
}
- if (brq.data.blocks > 1) {
- brq.data.flags |= MMC_DATA_MULTI;
- brq.mrq.stop = &brq.stop;
- } else {
- brq.mrq.stop = NULL;
- }
-
brq.data.sg = mq->sg;
brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg);
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index 8419489..2256d64 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -509,6 +509,7 @@ static int mmci_probe(struct amba_device
mmc->f_min = (host->mclk + 511) / 512;
mmc->f_max = min(host->mclk, fmax);
mmc->ocr_avail = plat->ocr_mask;
+ mmc->caps = MMC_CAP_MULTI_WRITE;
/*
* We can do SGIO
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index c1f021e..fd909ca 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -85,6 +85,7 @@ struct mmc_host {
unsigned long caps; /* Host capabilities */
#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
+#define MMC_CAP_MULTI_WRITE (1 << 1) /* Can do multiple block writes */
/* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php