[U-Boot] [PATCH 1/2] common: usb_storage : Implement logic to calculate optimal usb maximum trasfer blocks

Rajesh Bhagat rajesh.bhagat at nxp.com
Mon May 30 13:23:54 CEST 2016


Implements the logic to calculate the optimal usb maximum trasfer blocks
instead of sending USB_MAX_XFER_BLK blocks which is 65535 and 20 in case
of EHCI and other USB protocols respectively.

It adds an array of trasfer blocks that should be checked for success
starting from minimum to maximum, and rest of the read/write are
performed with that optimal value. It tries to increase/decrease the
blocks in follwing scenarios:

1.decrease blocks: when read/write for a particular number of blocks
fails.
2. increase blocks: when read/write for a particular number of blocks
pass and amount left to trasfer is greater than current number of
blocks.

Currently changes are done for EHCI where min = 4096 andmax = 65535
is taken. And for other cases code is left unchanged by keeping min
= max = 20.

Signed-off-by: Sriram Dash <sriram.dash at nxp.com>
Signed-off-by: Rajesh Bhagat <rajesh.bhagat at nxp.com>
---
 common/usb_storage.c |   54 ++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 43 insertions(+), 11 deletions(-)

diff --git a/common/usb_storage.c b/common/usb_storage.c
index 7e6e52d..7b5ad07 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -101,16 +101,15 @@ struct us_data {
 };
 
 #ifdef CONFIG_USB_EHCI
-/*
- * The U-Boot EHCI driver can handle any transfer length as long as there is
- * enough free heap space left, but the SCSI READ(10) and WRITE(10) commands are
- * limited to 65535 blocks.
- */
-#define USB_MAX_XFER_BLK	65535
+#define USB_XFER_BLK_TBL_SZ		5
+static unsigned short usb_xfer_blk_tbl[5] = {4096, 8192, 16384, 32768, 65535};
 #else
-#define USB_MAX_XFER_BLK	20
+#define USB_XFER_BLK_TBL_SZ		1
+static unsigned short usb_xfer_blk_tbl[1] = {20};
 #endif
 
+static unsigned short USB_MAX_XFER_BLK;
+
 #ifndef CONFIG_BLK
 static struct us_data usb_stor[USB_MAX_STOR_DEV];
 #endif
@@ -1117,7 +1116,8 @@ static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
 	unsigned short smallblks;
 	struct usb_device *udev;
 	struct us_data *ss;
-	int retry;
+	int retry, next = LOG2((USB_MAX_XFER_BLK + 1) / usb_xfer_blk_tbl[0]);
+	bool retry_flag = false;
 	ccb *srb = &usb_ccb;
 #ifdef CONFIG_BLK
 	struct blk_desc *block_dev;
@@ -1158,6 +1158,8 @@ static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
 		else
 			smallblks = (unsigned short) blks;
 retry_it:
+		debug("usb_read: retry #%d, xfer_blk %hu, smallblks %hu\n",
+		      retry, USB_MAX_XFER_BLK, smallblks);
 		if (smallblks == USB_MAX_XFER_BLK)
 			usb_show_progress();
 		srb->datalen = block_dev->blksz * smallblks;
@@ -1165,14 +1167,26 @@ retry_it:
 		if (usb_read_10(srb, ss, start, smallblks)) {
 			debug("Read ERROR\n");
 			usb_request_sense(srb, ss);
-			if (retry--)
+			if (retry--) {
+				/* decrease the USB_MAX_XFER_BLK */
+				if (next >  0) {
+					smallblks = usb_xfer_blk_tbl[--next];
+					USB_MAX_XFER_BLK = smallblks;
+				}
+				retry_flag = true;
 				goto retry_it;
+			}
 			blkcnt -= blks;
 			break;
 		}
 		start += smallblks;
 		blks -= smallblks;
 		buf_addr += srb->datalen;
+
+		/* try to increase the USB_MAX_XFER_BLK */
+		if (next < USB_XFER_BLK_TBL_SZ  - 1)
+			if (!retry_flag && usb_xfer_blk_tbl[next + 1] <= blks)
+				USB_MAX_XFER_BLK = usb_xfer_blk_tbl[++next];
 	} while (blks != 0);
 	ss->flags &= ~USB_READY;
 
@@ -1199,7 +1213,8 @@ static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
 	unsigned short smallblks;
 	struct usb_device *udev;
 	struct us_data *ss;
-	int retry;
+	int retry, next = LOG2((USB_MAX_XFER_BLK + 1) / usb_xfer_blk_tbl[0]);
+	bool retry_flag = false;
 	ccb *srb = &usb_ccb;
 #ifdef CONFIG_BLK
 	struct blk_desc *block_dev;
@@ -1244,6 +1259,8 @@ static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
 		else
 			smallblks = (unsigned short) blks;
 retry_it:
+		debug("usb_write: retry #%d, xfer_blk %hu, smallblks %hu\n",
+		      retry, USB_MAX_XFER_BLK, smallblks);
 		if (smallblks == USB_MAX_XFER_BLK)
 			usb_show_progress();
 		srb->datalen = block_dev->blksz * smallblks;
@@ -1251,14 +1268,26 @@ retry_it:
 		if (usb_write_10(srb, ss, start, smallblks)) {
 			debug("Write ERROR\n");
 			usb_request_sense(srb, ss);
-			if (retry--)
+			if (retry--) {
+				/* decrease the USB_MAX_XFER_BLK */
+				if (next >  0) {
+					smallblks = usb_xfer_blk_tbl[--next];
+					USB_MAX_XFER_BLK = smallblks;
+				}
+				retry_flag = true;
 				goto retry_it;
+			}
 			blkcnt -= blks;
 			break;
 		}
 		start += smallblks;
 		blks -= smallblks;
 		buf_addr += srb->datalen;
+
+		/* try to increase the USB_MAX_XFER_BLK */
+		if (next < USB_XFER_BLK_TBL_SZ  - 1)
+			if (!retry_flag && usb_xfer_blk_tbl[next + 1] <= blks)
+				USB_MAX_XFER_BLK = usb_xfer_blk_tbl[++next];
 	} while (blks != 0);
 	ss->flags &= ~USB_READY;
 
@@ -1331,6 +1360,9 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
 		break;
 	}
 
+	/* Initialize the current transfer blocks to minimum value */
+	USB_MAX_XFER_BLK = usb_xfer_blk_tbl[0];
+
 	/*
 	 * We are expecting a minimum of 2 endpoints - in and out (bulk).
 	 * An optional interrupt is OK (necessary for CBI protocol).
-- 
1.7.9.5



More information about the U-Boot mailing list