[PATCH v2 4/4] usb: Convert ad-hoc poll/timeout sequences in usb.c to iopoll

Ronan Dalton ronan.dalton at alliedtelesis.co.nz
Wed Feb 25 04:05:37 CET 2026


The usb_control_msg and usb_bulk_msg functions in usb.c use a while loop
and delay to wait for a USB control message to be processed. iopoll
provides a macro to do this for us which can be used instead.

Replace the while loops with calls to the read_poll_timeout macro. Also
add a check for timeout being negative at the start of the functions and
return -EINVAL in that case, since a negative timeout doesn't make
sense.

This also fixes a bug where usb_control_msg would check if timeout was
equal to 0 to determine if a timeout occurred, when it should have been
checking if it was -1 instead. This caused -1 to be returned by the
function in most cases when a timeout occurred instead of the correct
error code of -ETIMEDOUT.

Signed-off-by: Ronan Dalton <ronan.dalton at alliedtelesis.co.nz>
Cc: Marek Vasut <marex at denx.de>
Cc: Philip Oberfichtner <pro at denx.de>
---
Changes for v2:
- Changed headline, previously called:
  usb: Fix timeout check in usb_control_msg
- Fix timeout check bug by using iopoll instead of just fixing the if
  statement
- Update usb_bulk_msg to also use iopoll as well

Notes:
- usb_bulk_msg could be updated to return -ETIMEDOUT on the timeout
  case. Currently it looks like -EIO is returned if a timeout occurs and
  callers can't tell if a timeout occurred as such. The -EIO return code
  is also inconsistent with usb_control_msg which returns -1.

 common/usb.c | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/common/usb.c b/common/usb.c
index 1c139d86e90..4defda93a06 100644
--- a/common/usb.c
+++ b/common/usb.c
@@ -40,6 +40,7 @@
 #include <errno.h>
 #include <usb.h>
 #include <linux/delay.h>
+#include <linux/iopoll.h>
 
 #define USB_BUFSIZ	512
 
@@ -224,8 +225,12 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe,
 			void *data, unsigned short size, int timeout)
 {
 	ALLOC_CACHE_ALIGN_BUFFER(struct devrequest, setup_packet, 1);
+	volatile unsigned long usb_status;
 	int err;
 
+	if (timeout < 0)
+		return -EINVAL;
+
 	if ((timeout == 0) && (!asynch_allowed)) {
 		/* request for a asynch control pipe is not allowed */
 		return -EINVAL;
@@ -253,14 +258,12 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe,
 	 * interrupt handler may set the status when the USB operation has
 	 * been completed.
 	 */
-	while (timeout--) {
-		if (!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
-			break;
-		mdelay(1);
-	}
+	err = read_poll_timeout((volatile unsigned long), usb_status,
+				!(usb_status & USB_ST_NOT_PROC), 1000,
+				timeout * 1000UL, dev->status);
 
-	if (timeout == 0)
-		return -ETIMEDOUT;
+	if (err == -ETIMEDOUT)
+		return err;
 
 	if (dev->status)
 		return -1;
@@ -276,19 +279,22 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe,
 int usb_bulk_msg(struct usb_device *dev, unsigned int pipe,
 			void *data, int len, int *actual_length, int timeout)
 {
+	volatile unsigned long usb_status;
+
 	if (len < 0)
 		return -EINVAL;
 
+	if (timeout < 0)
+		return -EINVAL;
+
 	dev->status = USB_ST_NOT_PROC; /*not yet processed */
 
 	if (submit_bulk_msg(dev, pipe, data, len) < 0)
 		return -EIO;
 
-	while (timeout--) {
-		if (!((volatile unsigned long)dev->status & USB_ST_NOT_PROC))
-			break;
-		mdelay(1);
-	}
+	read_poll_timeout((volatile unsigned long), usb_status,
+			  !(usb_status & USB_ST_NOT_PROC), 1000,
+			  timeout * 1000UL, dev->status);
 
 	*actual_length = dev->act_len;
 
-- 
2.53.0



More information about the U-Boot mailing list