
Abort the request in case any of the tokens in the packet failed to complete transfer 10 times. This is a precaution needed so that we don't end in endless loop when scanning the bus with some braindead devices.
Signed-off-by: Marek Vasut marex@denx.de Cc: Chin Liang See clsee@altera.com Cc: Dinh Nguyen dinguyen@opensource.altera.com Cc: Hans de Goede hdegoede@redhat.com Cc: Stefan Roese sr@denx.de Cc: Stephen Warren swarren@nvidia.com --- drivers/usb/host/dwc2.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-)
diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index 8d3949e..27fcf7c 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -993,6 +993,8 @@ static int _submit_control_msg(struct dwc2_priv *priv, struct usb_device *dev, u8 pid; /* For CONTROL endpoint pid should start with DATA1 */ int status_direction; + int againctr = 0; + const int againmax = 10;
if (devnum == priv->root_hub_devnum) { dev->status = 0; @@ -1003,25 +1005,37 @@ static int _submit_control_msg(struct dwc2_priv *priv, struct usb_device *dev,
/* SETUP stage */ pid = DWC2_HC_PID_SETUP; - do { + againctr = 0; + while (true) { ret = chunk_msg(priv, dev, pipe, &pid, 0, setup, 8); - } while (ret == -EAGAIN); - if (ret) - return ret; + if (!ret) + break; + if (ret != -EAGAIN) + return ret; + if (againctr == againmax) + return -EINVAL; + againctr++; + };
/* DATA stage */ act_len = 0; if (buffer) { pid = DWC2_HC_PID_DATA1; - do { + againctr = 0; + while (true) { ret = chunk_msg(priv, dev, pipe, &pid, usb_pipein(pipe), buffer, len); act_len += dev->act_len; buffer += dev->act_len; len -= dev->act_len; - } while (ret == -EAGAIN); - if (ret) - return ret; + if (!ret) + break; + if (ret != -EAGAIN) + return ret; + if (againctr == againmax) + return -EINVAL; + againctr++; + }; status_direction = usb_pipeout(pipe); } else { /* No-data CONTROL always ends with an IN transaction */ @@ -1030,12 +1044,18 @@ static int _submit_control_msg(struct dwc2_priv *priv, struct usb_device *dev,
/* STATUS stage */ pid = DWC2_HC_PID_DATA1; - do { + againctr = 0; + while (true) { ret = chunk_msg(priv, dev, pipe, &pid, status_direction, priv->status_buffer, 0); - } while (ret == -EAGAIN); - if (ret) - return ret; + if (!ret) + break; + if (ret != -EAGAIN) + return ret; + if (againctr == againmax) + return -EINVAL; + againctr++; + };
dev->act_len = act_len;