Re: MMC performance
From: Pierre Ossman
Date: Mon Oct 11 2004 - 10:37:28 EST
Alan Cox wrote:
Only on retries. You can try and blast the lot out the first time then
on retries you write sector by sector.
Something like this? Gives more than double throughput here.
Index: linux-wbsd/drivers/mmc/mmc_block.c
===================================================================
--- linux-wbsd/drivers/mmc/mmc_block.c (revision 71)
+++ linux-wbsd/drivers/mmc/mmc_block.c (working copy)
@@ -166,9 +166,20 @@
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
int ret;
+ int failsafe;
if (mmc_card_claim_host(card))
goto cmd_err;
+
+ /*
+ * We first try transfering multiple blocks. If this fails
+ * we fall back to single block transfers.
+ *
+ * This gives us good performance when all is well and the
+ * possibility to determine which sector fails when all
+ * is not well.
+ */
+ failsafe = 0;
do {
struct mmc_blk_request brq;
@@ -188,15 +199,24 @@
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_R1B;
+
+ /*
+ * A multi-block transfer failed. Falling back to single
+ * blocks.
+ */
+ if (failsafe)
+ brq.data.blocks = 1;
+
+ ret = 1;
if (rq_data_dir(req) == READ) {
brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
brq.data.flags |= MMC_DATA_READ;
} else {
- brq.cmd.opcode = MMC_WRITE_BLOCK;
+ brq.cmd.opcode = brq.data.blocks > 1 ? MMC_WRITE_MULTIPLE_BLOCK :
+ MMC_WRITE_BLOCK;
brq.cmd.flags = MMC_RSP_R1B;
brq.data.flags |= MMC_DATA_WRITE;
- brq.data.blocks = 1;
}
brq.mrq.stop = brq.data.blocks > 1 ? &brq.stop : NULL;
@@ -204,19 +224,34 @@
if (brq.cmd.error) {
printk(KERN_ERR "%s: error %d sending read/write command\n",
req->rq_disk->disk_name, brq.cmd.error);
- goto cmd_err;
+ if (failsafe)
+ goto cmd_err;
+ else {
+ failsafe = 1;
+ continue;
+ }
}
if (brq.data.error) {
printk(KERN_ERR "%s: error %d transferring data\n",
req->rq_disk->disk_name, brq.data.error);
- goto cmd_err;
+ if (failsafe)
+ goto cmd_err;
+ else {
+ failsafe = 1;
+ continue;
+ }
}
if (brq.stop.error) {
printk(KERN_ERR "%s: error %d sending stop command\n",
req->rq_disk->disk_name, brq.stop.error);
- goto cmd_err;
+ if (failsafe)
+ goto cmd_err;
+ else {
+ failsafe = 1;
+ continue;
+ }
}
do {
@@ -229,7 +264,12 @@
if (err) {
printk(KERN_ERR "%s: error %d requesting status\n",
req->rq_disk->disk_name, err);
- goto cmd_err;
+ if (failsafe)
+ goto cmd_err;
+ else {
+ failsafe = 1;
+ continue;
+ }
}
} while (!(cmd.resp[0] & R1_READY_FOR_DATA));
@@ -255,6 +295,11 @@
end_that_request_last(req);
}
spin_unlock_irq(&md->lock);
+
+ /*
+ * Go back to bulk mode if in failsafe mode.
+ */
+ failsafe = 0;
} while (ret);
mmc_card_release_host(card);