app: aboot: Fix usb30 read API to handle short transfers

With USB3.0 max packet size changed to 1024 and if the data transfers
over USB are smaller than max packet size then USB3.0 treats it as
transfer complete. But sparse images would be downloaded in chunks
and the chunk size is 512 bytes, in such case fastboot should continue
data transfer instead of treating this as transfer completion.

Change-Id: I04f4b03d767f63f96cc363a66dc7446d7e666789
diff --git a/app/aboot/fastboot.c b/app/aboot/fastboot.c
index f905627..7965fea 100644
--- a/app/aboot/fastboot.c
+++ b/app/aboot/fastboot.c
@@ -61,6 +61,7 @@
 usb_controller_interface_t usb_if;
 
 #define MAX_USBFS_BULK_SIZE (32 * 1024)
+#define MAX_USBSS_BULK_SIZE (0x1000000)
 
 void boot_linux(void *bootimg, unsigned sz);
 static void fastboot_notify(struct udc_gadget *gadget, unsigned event);
@@ -182,10 +183,14 @@
 }
 
 #ifdef USB30_SUPPORT
-static int usb30_usb_read(void *buf, unsigned len)
+static int usb30_usb_read(void *_buf, unsigned len)
 {
 	int r;
 	struct udc_request req;
+	uint32_t xfer;
+	int count = 0;
+	uint32_t trans_len = len;
+	const char *buf = _buf;
 
 	ASSERT(buf);
 	ASSERT(len);
@@ -195,34 +200,53 @@
 
 	dprintf(SPEW, "usb_read(): len = %d\n", len);
 
-	req.buf      = (void*) PA((addr_t)buf);
-	req.length   = len;
-	req.complete = req_complete;
-
-	r = usb30_udc_request_queue(out, &req);
-	if (r < 0)
+	while (len > 0)
 	{
-		dprintf(CRITICAL, "usb_read() queue failed. r = %d\n", r);
-		goto oops;
-	}
-	event_wait(&txn_done);
+		xfer = (len > MAX_USBSS_BULK_SIZE) ? MAX_USBSS_BULK_SIZE : len;
 
-	if (txn_status < 0)
-	{
-		dprintf(CRITICAL, "usb_read() transaction failed. txn_status = %d\n",
-				txn_status);
-		goto oops;
-	}
+		req.buf      = (void*) PA((addr_t)buf);
+		req.length   = xfer;
+		req.complete = req_complete;
 
-	/* note: req->length is update by callback to reflect the amount of data
-	 * actually read.
-	 */
-	dprintf(SPEW, "usb_read(): DONE. req.length = %d\n", req.length);
+		r = usb30_udc_request_queue(out, &req);
+		if (r < 0)
+		{
+			dprintf(CRITICAL, "usb_read() queue failed. r = %d\n", r);
+			goto oops;
+		}
+		event_wait(&txn_done);
+
+		if (txn_status < 0)
+		{
+			dprintf(CRITICAL, "usb_read() transaction failed. txn_status = %d\n",
+					txn_status);
+			goto oops;
+		}
+
+		count += req.length;
+		buf += req.length;
+		len -= req.length;
+
+		/* note: req.length is update by callback to reflect the amount of data
+		 * actually read.
+		 */
+		dprintf(SPEW, "usb_read(): DONE. req.length = %d\n\n", req.length);
+
+		/* For USB3.0 if the data transfer is less than MaxpacketSize, its
+		 * short packet and DWC layer generates transfer complete. App layer
+		 * shold handle this and continue trasnferring the data instead of treating
+		 * this as a transfer complete. This case is not applicable for transfers
+		 * which involve protocol communication to exchange information whose length
+		 * is always equal to MAX_RSP_SIZE. This check ensures that we dont abort
+		 * data transfers on short packet.
+		 */
+		if (req.length != xfer && trans_len == MAX_RSP_SIZE) break;
+	}
 
 	/* invalidate any cached buf data (controller updates main memory) */
-	arch_invalidate_cache_range((addr_t) buf, len);
+	arch_invalidate_cache_range((addr_t) _buf, count);
 
-	return req.length;
+	return count;
 
 oops:
 	fastboot_state = STATE_ERROR;