[U-Boot] [PATCH 3/7] usb: dwc2: Throttle the setup packet resending

Marek Vasut
2016-05-03T20:51:16Z

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;

--
2.7.0