Skip to contentSkip to conversation

Bulk transfers (round 2)

PATCH In review Pierre Ossman 1 participant 2 messages Mar 16, 2005 MMC, SD and SDIO

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Bulk transfers (round 2)

I didn't get any response for this one either ;)

This is only a performance boost so it is less critical. It is very nice to have though since the performance gain is substancial (>100%).

It should not pose any problems with data loss, which was your primary concern. It backs down to single block transfers when an error is detected.

This patch has been downloaded almost 500 times and there have been no errors reported that were related directly to the patch. The two errors reported from using this was in the driver and with a buggy card (the same one that needs the power cycle patch).

Kconfig default here is 'no' but 'yes' should be considered once it has been tested on some more controllers.

Rgds
Pierre

#1 lore raw

it might help if I include the actual patch...

drivers/mmc/mmc_block.c +61 -6
Index: linux-wbsd/drivers/mmc/mmc_block.c
===================================================================
@@ -166,9 +166,25 @@
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
 	int ret;
+	
+#ifdef CONFIG_MMC_BULKTRANSFER
+	int failsafe;
+#endif
 
 	if (mmc_card_claim_host(card))
 		goto cmd_err;
+	
+#ifdef CONFIG_MMC_BULKTRANSFER
+	/*
+	 * 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;
+#endif
 
 	do {
 		struct mmc_blk_request brq;
@@ -189,14 +205,32 @@
 		brq.stop.arg = 0;
 		brq.stop.flags = MMC_RSP_R1B;
 
+#ifdef CONFIG_MMC_BULKTRANSFER		
+		/*
+		 * A multi-block transfer failed. Falling back to single
+		 * blocks.
+		 */
+		if (failsafe)
+			brq.data.blocks = 1;
+		
+#else
+		/*
+		 * Writes are done one sector at a time.
+		 */
+		if (rq_data_dir(req) != READ)
+			brq.data.blocks = 1;
+#endif
+		
+		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 +238,19 @@
 		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;
+			goto cmd_fail;
 		}
 
 		if (brq.data.error) {
 			printk(KERN_ERR "%s: error %d transferring data\n",
 			       req->rq_disk->disk_name, brq.data.error);
-			goto cmd_err;
+			goto cmd_fail;
 		}
 
 		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;
+			goto cmd_fail;
 		}
 
 		do {
@@ -229,7 +263,7 @@
 			if (err) {
 				printk(KERN_ERR "%s: error %d requesting status\n",
 				       req->rq_disk->disk_name, err);
-				goto cmd_err;
+				goto cmd_fail;
 			}
 		} while (!(cmd.resp[0] & R1_READY_FOR_DATA));
 
@@ -255,6 +289,27 @@
 			end_that_request_last(req);
 		}
 		spin_unlock_irq(&md->lock);
+		
+#ifdef CONFIG_MMC_BULKTRANSFER
+		/*
+		 * Go back to bulk mode if in failsafe mode.
+		 */
+		failsafe = 0;
+#endif
+
+		continue;
+
+ cmd_fail:
+
+#ifdef CONFIG_MMC_BULKTRANSFER
+		if (failsafe)
+	 		goto cmd_err;
+	 	else
+	 		failsafe = 1;
+#else
+ 		goto cmd_err;
+#endif
+
 	} while (ret);
 
 	mmc_card_release_host(card);
drivers/mmc/Kconfig +9 -0
Index: linux-wbsd/drivers/mmc/Kconfig
===================================================================
@@ -41,6 +41,15 @@
 	  mount the filesystem. Almost everyone wishing MMC support
 	  should say Y or M here.
 
+config MMC_BULKTRANSFER
+	bool "Multi-block writes (EXPERIMENTAL)"
+	depends on MMC_BLOCK != n && EXPERIMENTAL
+	default n
+	help
+	  By default all writes are done one sector at a time. Enable
+	  this option to transfer as large blocks as the host supports.
+	  The transfer speed is in most cases doubled.
+
 config MMC_ARMMMCI
 	tristate "ARM AMBA Multimedia Card Interface support"
 	depends on ARM_AMBA && MMC