Skip to contentSkip to conversation

dm: usb: Add a new USB controller operation 'get_max_xfer_size'

PATCH New Bin Meng 4 participants 15 messages Sep 7, 2017 – Sep 28, 2017

Subsystems (3)
lore
Share & tools
lore

Bin Meng

author
#0 lore raw

PATCH 1/5 dm: usb: Add a new USB controller operation 'get_max_xfer_size'

The HCD may have limitation on the maximum bytes to be transferred in a USB transfer. USB class driver needs to be aware of this.

---

 drivers/usb/host/usb-uclass.c | 11 +++++++++++
 include/usb.h                 | 22 +++++++++++++++++++++-
 2 files changed, 32 insertions(+), 1 deletion(-)
drivers/usb/host/usb-uclass.c +11 -0
index 0b8a501..bc44fc3 100644
@@ -150,6 +150,17 @@ int usb_update_hub_device(struct usb_device *udev)
 	return ops->update_hub_device(bus, udev);
 }
 
+int usb_get_max_xfer_size(struct usb_device *udev, size_t *size)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->get_max_xfer_size)
+		return -ENOSYS;
+
+	return ops->get_max_xfer_size(bus, size);
+}
+
 int usb_stop(void)
 {
 	struct udevice *bus;
include/usb.h +21 -1
index fad0401..0ddc082 100644
@@ -766,6 +766,14 @@ struct dm_usb_ops {
 	 * representation of this hub can be updated (xHCI)
 	 */
 	int (*update_hub_device)(struct udevice *bus, struct usb_device *udev);
+
+	/**
+	 * get_max_xfer_size() - Get HCD's maximum transfer bytes
+	 *
+	 * The HCD may have limitation on the maximum bytes to be transferred
+	 * in a USB transfer. USB class driver needs to be aware of this.
+	 */
+	int (*get_max_xfer_size)(struct udevice *bus, size_t *size);
 };
 
 #define usb_get_ops(dev)	((struct dm_usb_ops *)(dev)->driver->ops)
@@ -939,7 +947,7 @@ int usb_new_device(struct usb_device *dev);
 int usb_alloc_device(struct usb_device *dev);
 
 /**
- * update_hub_device() - Update HCD's internal representation of hub
+ * usb_update_hub_device() - Update HCD's internal representation of hub
  *
  * After a hub descriptor is fetched, notify HCD so that its internal
  * representation of this hub can be updated.
@@ -950,6 +958,18 @@ int usb_alloc_device(struct usb_device *dev);
 int usb_update_hub_device(struct usb_device *dev);
 
 /**
+ * usb_get_max_xfer_size() - Get HCD's maximum transfer bytes
+ *
+ * The HCD may have limitation on the maximum bytes to be transferred
+ * in a USB transfer. USB class driver needs to be aware of this.
+ *
+ * @dev:		USB device
+ * @size:		maximum transfer bytes
+ * @return 0 if OK, -ve on error
+ */
+int usb_get_max_xfer_size(struct usb_device *dev, size_t *size);
+
+/**
  * usb_emul_setup_device() - Set up a new USB device emulation
  *
  * This is normally called when a new emulation device is bound. It tells
Signature · 1 line
2.9.2
author
#1 lore raw

PATCH 2/5 dm: usb: xhci: Implement get_max_xfer_size() operation

xHCD allocates one segment which includes 64 TRBs for each endpoint and the last TRB in this segment is configured as a link TRB to form a TRB ring. Each TRB can transfer up to 64K bytes, however data buffers referenced by transfer TRBs shall not span 64KB boundaries. Hence the maximum number of TRBs we can use in one transfer is 62.

---

 drivers/usb/host/xhci.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
drivers/usb/host/xhci.c +15 -0
index 9b82ee5..04eb1eb 100644
@@ -1228,6 +1228,20 @@ static int xhci_update_hub_device(struct udevice *dev, struct usb_device *udev)
 	return xhci_configure_endpoints(udev, false);
 }
 
+static int xhci_get_max_xfer_size(struct udevice *dev, size_t *size)
+{
+	/*
+	 * xHCD allocates one segment which includes 64 TRBs for each endpoint
+	 * and the last TRB in this segment is configured as a link TRB to form
+	 * a TRB ring. Each TRB can transfer up to 64K bytes, however data
+	 * buffers referenced by transfer TRBs shall not span 64KB boundaries.
+	 * Hence the maximum number of TRBs we can use in one transfer is 62.
+	 */
+	*size = (TRBS_PER_SEGMENT - 2) * TRB_MAX_BUFF_SIZE;
+
+	return 0;
+}
+
 int xhci_register(struct udevice *dev, struct xhci_hccr *hccr,
 		  struct xhci_hcor *hcor)
 {
@@ -1281,6 +1295,7 @@ struct dm_usb_ops xhci_usb_ops = {
 	.interrupt = xhci_submit_int_msg,
 	.alloc_device = xhci_alloc_device,
 	.update_hub_device = xhci_update_hub_device,
+	.get_max_xfer_size  = xhci_get_max_xfer_size,
 };
 
 #endif
Signature · 1 line
2.9.2
#2 lore raw

PATCH 2/5 dm: usb: xhci: Implement get_max_xfer_size() operation

Quoted 7 lines · Bin Meng

xHCD allocates one segment which includes 64 TRBs for each endpoint and the last TRB in this segment is configured as a link TRB to form a TRB ring. Each TRB can transfer up to 64K bytes, however data buffers referenced by transfer TRBs shall not span 64KB boundaries. Hence the maximum number of TRBs we can use in one transfer is 62.

Thank,
Stefan

author
#3 lore raw

PATCH 3/5 dm: usb: ehci: Implement get_max_xfer_size() operation

In reply to Bin Meng

EHCD can handle any transfer length as long as there is enough free heap space left, hence set the theoretical max number SIZE_MAX.

---

 drivers/usb/host/ehci-hcd.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
drivers/usb/host/ehci-hcd.c +12 -0
index 3243c1d..be3e842 100644
@@ -1596,6 +1596,17 @@ static int ehci_destroy_int_queue(struct udevice *dev, struct usb_device *udev,
 	return _ehci_destroy_int_queue(udev, queue);
 }
 
+static int ehci_get_max_xfer_size(struct udevice *dev, size_t *size)
+{
+	/*
+	 * EHCD can handle any transfer length as long as there is enough
+	 * free heap space left, hence set the theoretical max number here.
+	 */
+	*size = SIZE_MAX;
+
+	return 0;
+}
+
 int ehci_register(struct udevice *dev, struct ehci_hccr *hccr,
 		  struct ehci_hcor *hcor, const struct ehci_ops *ops,
 		  uint tweaks, enum usb_init_type init)
@@ -1658,6 +1669,7 @@ struct dm_usb_ops ehci_usb_ops = {
 	.create_int_queue = ehci_create_int_queue,
 	.poll_int_queue = ehci_poll_int_queue,
 	.destroy_int_queue = ehci_destroy_int_queue,
+	.get_max_xfer_size  = ehci_get_max_xfer_size,
 };
 
 #endif
Signature · 1 line
2.9.2
author
#5 lore raw

PATCH 4/5 usb: storage: Refactor to use max_xfer_blk from struct us_data

In reply to Bin Meng

This adds a new memeber max_xfer_blk in struct us_data to record the maximum number of transfer blocks for the storage device.

It is set per HCD setting, and so far is to 65535 for EHCD and 20 for everything else.

---

 common/usb_storage.c | 49 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 30 insertions(+), 19 deletions(-)
common/usb_storage.c +30 -19
index df0b057..957ccdb 100644
@@ -98,19 +98,9 @@ struct us_data {
 	struct scsi_cmd	*srb;			/* current srb */
 	trans_reset	transport_reset;	/* reset routine */
 	trans_cmnd	transport;		/* transport routine */
+	unsigned short	max_xfer_blk;		/* maximum transfer blocks */
 };
 
-#ifdef CONFIG_USB_EHCI_HCD
-/*
- * 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
-#else
-#define USB_MAX_XFER_BLK	20
-#endif
-
 #ifndef CONFIG_BLK
 static struct us_data usb_stor[USB_MAX_STOR_DEV];
 #endif
@@ -949,6 +939,23 @@ do_retry:
 	return USB_STOR_TRANSPORT_FAILED;
 }
 
+static void usb_stor_set_max_xfer_blk(struct us_data *us)
+{
+	unsigned short blk;
+
+#ifdef CONFIG_USB_EHCI_HCD
+	/*
+	 * 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.
+	 */
+	blk = USHRT_MAX;
+#else
+	blk = 20;
+#endif
+
+	us->max_xfer_blk = blk;
+}
 
 static int usb_inquiry(struct scsi_cmd *srb, struct us_data *ss)
 {
@@ -1150,12 +1157,12 @@ static unsigned long usb_stor_read(struct blk_desc *block_dev, lbaint_t blknr,
 		/* XXX need some comment here */
 		retry = 2;
 		srb->pdata = (unsigned char *)buf_addr;
-		if (blks > USB_MAX_XFER_BLK)
-			smallblks = USB_MAX_XFER_BLK;
+		if (blks > ss->max_xfer_blk)
+			smallblks = ss->max_xfer_blk;
 		else
 			smallblks = (unsigned short) blks;
 retry_it:
-		if (smallblks == USB_MAX_XFER_BLK)
+		if (smallblks == ss->max_xfer_blk)
 			usb_show_progress();
 		srb->datalen = block_dev->blksz * smallblks;
 		srb->pdata = (unsigned char *)buf_addr;
@@ -1178,7 +1185,7 @@ retry_it:
 	      start, smallblks, buf_addr);
 
 	usb_disable_asynch(0); /* asynch transfer allowed */
-	if (blkcnt >= USB_MAX_XFER_BLK)
+	if (blkcnt >= ss->max_xfer_blk)
 		debug("\n");
 	return blkcnt;
 }
@@ -1236,12 +1243,12 @@ static unsigned long usb_stor_write(struct blk_desc *block_dev, lbaint_t blknr,
 		 */
 		retry = 2;
 		srb->pdata = (unsigned char *)buf_addr;
-		if (blks > USB_MAX_XFER_BLK)
-			smallblks = USB_MAX_XFER_BLK;
+		if (blks > ss->max_xfer_blk)
+			smallblks = ss->max_xfer_blk;
 		else
 			smallblks = (unsigned short) blks;
 retry_it:
-		if (smallblks == USB_MAX_XFER_BLK)
+		if (smallblks == ss->max_xfer_blk)
 			usb_show_progress();
 		srb->datalen = block_dev->blksz * smallblks;
 		srb->pdata = (unsigned char *)buf_addr;
@@ -1263,7 +1270,7 @@ retry_it:
 	      PRIxPTR "\n", start, smallblks, buf_addr);
 
 	usb_disable_asynch(0); /* asynch transfer allowed */
-	if (blkcnt >= USB_MAX_XFER_BLK)
+	if (blkcnt >= ss->max_xfer_blk)
 		debug("\n");
 	return blkcnt;
 
@@ -1384,6 +1391,10 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
 		ss->irqmaxp = usb_maxpacket(dev, ss->irqpipe);
 		dev->irq_handle = usb_stor_irq;
 	}
+
+	/* Set the maximum transfer size per host controller setting */
+	usb_stor_set_max_xfer_blk(ss);
+
 	dev->privptr = (void *)ss;
 	return 1;
 }
Signature · 1 line
2.9.2
#6 lore raw

PATCH 4/5 usb: storage: Refactor to use max_xfer_blk from struct us_data

Quoted 7 lines · Bin Meng

This adds a new memeber max_xfer_blk in struct us_data to record the maximum number of transfer blocks for the storage device.

It is set per HCD setting, and so far is to 65535 for EHCD and 20 for everything else.

Thanks,
Stefan

author
#7 lore raw

PATCH 5/5 dm: usb: storage: Fix broken read/write when both EHCD and xHCD are enabled

In reply to Bin Meng

When EHCD and xHCD are enabled at the same time, USB storage device driver will fail to read/write from/to the storage device attached to the xHCI interface, due to its transfer blocks exceeds the xHCD driver limitation.

With driver model, we have an API to get the controller's maximum transfer size and we can use that to determine the storage driver's capability of read/write.

Note: the non-DM version driver is still broken with xHCD and the intent here is not to fix the non-DM one, since the xHCD itself is already broken in places like 3.0 hub support, etc.

---

 common/usb_storage.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)
common/usb_storage.c +17 -2
index 957ccdb..a57570b 100644
@@ -939,10 +939,14 @@ do_retry:
 	return USB_STOR_TRANSPORT_FAILED;
 }
 
-static void usb_stor_set_max_xfer_blk(struct us_data *us)
+static void usb_stor_set_max_xfer_blk(struct usb_device *udev,
+				      struct us_data *us)
 {
 	unsigned short blk;
+	size_t __maybe_unused size;
+	int __maybe_unused ret;
 
+#ifndef CONFIG_DM_USB
 #ifdef CONFIG_USB_EHCI_HCD
 	/*
 	 * The U-Boot EHCI driver can handle any transfer length as long as
@@ -953,6 +957,17 @@ static void usb_stor_set_max_xfer_blk(struct us_data *us)
 #else
 	blk = 20;
 #endif
+#else
+	ret = usb_get_max_xfer_size(udev, (size_t *)&size);
+	if (ret < 0) {
+		/* unimplemented, let's use default 20 */
+		blk = 20;
+	} else {
+		if (size > USHRT_MAX * 512)
+			blk = USHRT_MAX;
+		blk = size / 512;
+	}
+#endif
 
 	us->max_xfer_blk = blk;
 }
@@ -1393,7 +1408,7 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,
 	}
 
 	/* Set the maximum transfer size per host controller setting */
-	usb_stor_set_max_xfer_blk(ss);
+	usb_stor_set_max_xfer_blk(dev, ss);
 
 	dev->privptr = (void *)ss;
 	return 1;
Signature · 1 line
2.9.2
#8 lore raw

PATCH 5/5 dm: usb: storage: Fix broken read/write when both EHCD and xHCD are enabled

Quoted 9 lines · Bin Meng

When EHCD and xHCD are enabled at the same time, USB storage device driver will fail to read/write from/to the storage device attached to the xHCI interface, due to its transfer blocks exceeds the xHCD driver limitation.

With driver model, we have an API to get the controller's maximum transfer size and we can use that to determine the storage driver's capability of read/write.

Quoted 5 lines

Note: the non-DM version driver is still broken with xHCD and the intent here is not to fix the non-DM one, since the xHCD itself is already broken in places like 3.0 hub support, etc.

Thanks,
Stefan

#9 lore raw

PATCH 5/5 dm: usb: storage: Fix broken read/write when both EHCD and xHCD are enabled

In reply to Bin Meng
Quoted 15 lines · Bin Meng

When EHCD and xHCD are enabled at the same time, USB storage device driver will fail to read/write from/to the storage device attached to the xHCI interface, due to its transfer blocks exceeds the xHCD driver limitation.

With driver model, we have an API to get the controller's maximum transfer size and we can use that to determine the storage driver's capability of read/write.

Note: the non-DM version driver is still broken with xHCD and the intent here is not to fix the non-DM one, since the xHCD itself is already broken in places like 3.0 hub support, etc.

[snip]

Quoted 5 lines
common/usb_storage.c +1 -0
@@ -953,6 +957,17 @@ static void usb_stor_set_max_xfer_blk(struct us_data *us)
 #else
 	blk = 20;
 #endif
+#else

common/usb_storage.c static void usb_stor_set_max_xfer_blk(struct us_data *us) · line 970

Quoted 10 lines
common/usb_storage.c +10 -0
+	ret = usb_get_max_xfer_size(udev, (size_t *)&size);
+	if (ret < 0) {
+		/* unimplemented, let's use default 20 */
+		blk = 20;
+	} else {
+		if (size > USHRT_MAX * 512)
+			blk = USHRT_MAX;
+		blk = size / 512;
+	}
+#endif

So, Coverity saw this and found an issue (CID 167250), and I was going to just fix it, but I'm not sure. The problem is that we check size > (USHRT_MAX * 512), and then assign blk. Then, we always assign blk, so the test above isn't used. But my background recollection is that there's a real issue that's being addressed here. Can we really just always say blk = size / 512 in this case, or did we want to be shifting size not blk under the if? Thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170927/c965f96d/attachment.sig>
author
#10 lore raw

PATCH 5/5 dm: usb: storage: Fix broken read/write when both EHCD and xHCD are enabled

Hi Tom,

Quoted 34 lines · Tom Rini
Quoted 15 lines · Bin Meng

When EHCD and xHCD are enabled at the same time, USB storage device driver will fail to read/write from/to the storage device attached to the xHCI interface, due to its transfer blocks exceeds the xHCD driver limitation.

With driver model, we have an API to get the controller's maximum transfer size and we can use that to determine the storage driver's capability of read/write.

Note: the non-DM version driver is still broken with xHCD and the intent here is not to fix the non-DM one, since the xHCD itself is already broken in places like 3.0 hub support, etc.

[snip]

Quoted 5 lines
common/usb_storage.c +1 -0
@@ -953,6 +957,17 @@ static void usb_stor_set_max_xfer_blk(struct us_data *us)
 #else
      blk = 20;
 #endif
+#else

common/usb_storage.c static void usb_stor_set_max_xfer_blk(struct us_data *us) · line 970

Quoted 10 lines
common/usb_storage.c +10 -0
+     ret = usb_get_max_xfer_size(udev, (size_t *)&size);
+     if (ret < 0) {
+             /* unimplemented, let's use default 20 */
+             blk = 20;
+     } else {
+             if (size > USHRT_MAX * 512)
+                     blk = USHRT_MAX;
+             blk = size / 512;
+     }
+#endif
Quoted 7 lines

So, Coverity saw this and found an issue (CID 167250), and I was going to just fix it, but I'm not sure. The problem is that we check size > (USHRT_MAX * 512), and then assign blk. Then, we always assign blk, so the test above isn't used. But my background recollection is that there's a real issue that's being addressed here. Can we really just always say blk = size / 512 in this case, or did we want to be shifting size not blk under the if? Thanks!

Did this patch applied to anywhere? I see it is in the usb tree, but not in the u-boot/master.

The fix should be:

             if (size > USHRT_MAX * 512)
                     size = USHRT_MAX * 512;

Regards,
Bin

#11 lore raw

PATCH 5/5 dm: usb: storage: Fix broken read/write when both EHCD and xHCD are enabled

Quoted 45 lines · Bin Meng

Hi Tom,

Quoted 34 lines · Tom Rini
Quoted 15 lines · Bin Meng

When EHCD and xHCD are enabled at the same time, USB storage device driver will fail to read/write from/to the storage device attached to the xHCI interface, due to its transfer blocks exceeds the xHCD driver limitation.

With driver model, we have an API to get the controller's maximum transfer size and we can use that to determine the storage driver's capability of read/write.

Note: the non-DM version driver is still broken with xHCD and the intent here is not to fix the non-DM one, since the xHCD itself is already broken in places like 3.0 hub support, etc.

[snip]

Quoted 5 lines
common/usb_storage.c +1 -0
@@ -953,6 +957,17 @@ static void usb_stor_set_max_xfer_blk(struct us_data *us)
 #else
      blk = 20;
 #endif
+#else

common/usb_storage.c static void usb_stor_set_max_xfer_blk(struct us_data *us) · line 970

Quoted 10 lines
common/usb_storage.c +10 -0
+     ret = usb_get_max_xfer_size(udev, (size_t *)&size);
+     if (ret < 0) {
+             /* unimplemented, let's use default 20 */
+             blk = 20;
+     } else {
+             if (size > USHRT_MAX * 512)
+                     blk = USHRT_MAX;
+             blk = size / 512;
+     }
+#endif
Quoted 7 lines

So, Coverity saw this and found an issue (CID 167250), and I was going to just fix it, but I'm not sure. The problem is that we check size > (USHRT_MAX * 512), and then assign blk. Then, we always assign blk, so the test above isn't used. But my background recollection is that there's a real issue that's being addressed here. Can we really just always say blk = size / 512 in this case, or did we want to be shifting size not blk under the if? Thanks!

Quoted 7 lines

Did this patch applied to anywhere? I see it is in the usb tree, but not in the u-boot/master.

The fix should be:

             if (size > USHRT_MAX * 512)
                     size = USHRT_MAX * 512;

It's in usb/master, and will be in master itself shortly. Please submit a patch that corrects this and has the Reported-by for Coverity. Marek, do you want to take it via your tree or should I just grab it? Thanks!

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170927/8d89853d/attachment.sig>
#12 lore raw

PATCH 5/5 dm: usb: storage: Fix broken read/write when both EHCD and xHCD are enabled

Quoted 49 lines · Tom Rini
Quoted 48 lines · Bin Meng

Hi Tom,

Quoted 34 lines · Tom Rini
Quoted 15 lines · Bin Meng

When EHCD and xHCD are enabled at the same time, USB storage device driver will fail to read/write from/to the storage device attached to the xHCI interface, due to its transfer blocks exceeds the xHCD driver limitation.

With driver model, we have an API to get the controller's maximum transfer size and we can use that to determine the storage driver's capability of read/write.

Note: the non-DM version driver is still broken with xHCD and the intent here is not to fix the non-DM one, since the xHCD itself is already broken in places like 3.0 hub support, etc.

[snip]

Quoted 5 lines
common/usb_storage.c +1 -0
@@ -953,6 +957,17 @@ static void usb_stor_set_max_xfer_blk(struct us_data *us)
 #else
      blk = 20;
 #endif
+#else

common/usb_storage.c static void usb_stor_set_max_xfer_blk(struct us_data *us) · line 970

Quoted 10 lines
common/usb_storage.c +10 -0
+     ret = usb_get_max_xfer_size(udev, (size_t *)&size);
+     if (ret < 0) {
+             /* unimplemented, let's use default 20 */
+             blk = 20;
+     } else {
+             if (size > USHRT_MAX * 512)
+                     blk = USHRT_MAX;
+             blk = size / 512;
+     }
+#endif
Quoted 7 lines

So, Coverity saw this and found an issue (CID 167250), and I was going to just fix it, but I'm not sure. The problem is that we check size > (USHRT_MAX * 512), and then assign blk. Then, we always assign blk, so the test above isn't used. But my background recollection is that there's a real issue that's being addressed here. Can we really just always say blk = size / 512 in this case, or did we want to be shifting size not blk under the if? Thanks!

Did this patch applied to anywhere? I see it is in the usb tree, but not in the u-boot/master.

Quoted 8 lines
Quoted 4 lines

The fix should be:

             if (size > USHRT_MAX * 512)
                     size = USHRT_MAX * 512;

It's in usb/master, and will be in master itself shortly. Please submit a patch that corrects this and has the Reported-by for Coverity. Marek, do you want to take it via your tree or should I just grab it? Thanks!

A USB patch should always go through -usb , I believe that's an established practice .

Signature · 2 lines
Best regards,
Marek Vasut
#13 lore raw

PATCH 5/5 dm: usb: storage: Fix broken read/write when both EHCD and xHCD are enabled

Quoted 55 lines · Marek Vasut
Quoted 54 lines · Tom Rini
Quoted 52 lines · Bin Meng

Hi Tom,

Quoted 34 lines · Tom Rini
Quoted 15 lines · Bin Meng

When EHCD and xHCD are enabled at the same time, USB storage device driver will fail to read/write from/to the storage device attached to the xHCI interface, due to its transfer blocks exceeds the xHCD driver limitation.

With driver model, we have an API to get the controller's maximum transfer size and we can use that to determine the storage driver's capability of read/write.

Note: the non-DM version driver is still broken with xHCD and the intent here is not to fix the non-DM one, since the xHCD itself is already broken in places like 3.0 hub support, etc.

[snip]

Quoted 5 lines
common/usb_storage.c +1 -0
@@ -953,6 +957,17 @@ static void usb_stor_set_max_xfer_blk(struct us_data *us)
 #else
      blk = 20;
 #endif
+#else

common/usb_storage.c static void usb_stor_set_max_xfer_blk(struct us_data *us) · line 970

Quoted 10 lines
common/usb_storage.c +10 -0
+     ret = usb_get_max_xfer_size(udev, (size_t *)&size);
+     if (ret < 0) {
+             /* unimplemented, let's use default 20 */
+             blk = 20;
+     } else {
+             if (size > USHRT_MAX * 512)
+                     blk = USHRT_MAX;
+             blk = size / 512;
+     }
+#endif
Quoted 7 lines

So, Coverity saw this and found an issue (CID 167250), and I was going to just fix it, but I'm not sure. The problem is that we check size > (USHRT_MAX * 512), and then assign blk. Then, we always assign blk, so the test above isn't used. But my background recollection is that there's a real issue that's being addressed here. Can we really just always say blk = size / 512 in this case, or did we want to be shifting size not blk under the if? Thanks!

Did this patch applied to anywhere? I see it is in the usb tree, but not in the u-boot/master.

The fix should be:

             if (size > USHRT_MAX * 512)
                     size = USHRT_MAX * 512;
Quoted 6 lines
Quoted 3 lines

It's in usb/master, and will be in master itself shortly. Please submit a patch that corrects this and has the Reported-by for Coverity. Marek, do you want to take it via your tree or should I just grab it? Thanks!

A USB patch should always go through -usb , I believe that's an established practice .

Aside from when you tell me to just pick up a fix directly, for whatever appropriate reason, yes. Which is why I asked.

Signature · 8 lines
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170927/1a8f07c6/attachment.sig>
#14 lore raw

PATCH 1/5 dm: usb: Add a new USB controller operation 'get_max_xfer_size'

In reply to Bin Meng

Hi Bin,

thanks for working on this. Without these 5 patches applied, loading files via "load" command from USB sticks results in U-Boot crashes. With all these 5 patches applied, loading via FS now works as expected. :)

So:

Thank,
Stefan

Quoted 80 lines · Bin Meng

The HCD may have limitation on the maximum bytes to be transferred in a USB transfer. USB class driver needs to be aware of this.

---

  drivers/usb/host/usb-uclass.c | 11 +++++++++++
  include/usb.h                 | 22 +++++++++++++++++++++-
  2 files changed, 32 insertions(+), 1 deletion(-)
drivers/usb/host/usb-uclass.c +11 -0
index 0b8a501..bc44fc3 100644
@@ -150,6 +150,17 @@ int usb_update_hub_device(struct usb_device *udev)
  	return ops->update_hub_device(bus, udev);
  }
 
+int usb_get_max_xfer_size(struct usb_device *udev, size_t *size)
+{
+	struct udevice *bus = udev->controller_dev;
+	struct dm_usb_ops *ops = usb_get_ops(bus);
+
+	if (!ops->get_max_xfer_size)
+		return -ENOSYS;
+
+	return ops->get_max_xfer_size(bus, size);
+}
+
  int usb_stop(void)
  {
  	struct udevice *bus;
include/usb.h +21 -1
index fad0401..0ddc082 100644
@@ -766,6 +766,14 @@ struct dm_usb_ops {
  	 * representation of this hub can be updated (xHCI)
  	 */
  	int (*update_hub_device)(struct udevice *bus, struct usb_device *udev);
+
+	/**
+	 * get_max_xfer_size() - Get HCD's maximum transfer bytes
+	 *
+	 * The HCD may have limitation on the maximum bytes to be transferred
+	 * in a USB transfer. USB class driver needs to be aware of this.
+	 */
+	int (*get_max_xfer_size)(struct udevice *bus, size_t *size);
  };
 
  #define usb_get_ops(dev)	((struct dm_usb_ops *)(dev)->driver->ops)
@@ -939,7 +947,7 @@ int usb_new_device(struct usb_device *dev);
  int usb_alloc_device(struct usb_device *dev);
 
  /**
- * update_hub_device() - Update HCD's internal representation of hub
+ * usb_update_hub_device() - Update HCD's internal representation of hub
   *
   * After a hub descriptor is fetched, notify HCD so that its internal
   * representation of this hub can be updated.
@@ -950,6 +958,18 @@ int usb_alloc_device(struct usb_device *dev);
  int usb_update_hub_device(struct usb_device *dev);
 
  /**
+ * usb_get_max_xfer_size() - Get HCD's maximum transfer bytes
+ *
+ * The HCD may have limitation on the maximum bytes to be transferred
+ * in a USB transfer. USB class driver needs to be aware of this.
+ *
+ * @dev:		USB device
+ * @size:		maximum transfer bytes
+ * @return 0 if OK, -ve on error
+ */
+int usb_get_max_xfer_size(struct usb_device *dev, size_t *size);
+
+/**
   * usb_emul_setup_device() - Set up a new USB device emulation
   *
   * This is normally called when a new emulation device is bound. It tells