aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Balbi <felipe.balbi@linux.intel.com>2016-10-04 15:14:43 +0300
committerMister Oyster <oysterized@gmail.com>2017-04-11 10:58:06 +0200
commit5c9a51eaacb53ad2f52025f0ebec365731b920cc (patch)
tree4fe0813c8718304d01379ee130689032ac8087ba
parenteccbd7397b7a156d8a3afbbb97d2ff27152f132d (diff)
usb: gadget: function: u_ether: don't starve tx request queue
commit 6c83f77278f17a7679001027e9231291c20f0d8a upstream. If we don't guarantee that we will always get an interrupt at least when we're queueing our very last request, we could fall into situation where we queue every request with 'no_interrupt' set. This will cause the link to get stuck. The behavior above has been triggered with g_ether and dwc3. Reported-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com> Signed-off-by: Willy Tarreau <w@1wt.eu>
-rw-r--r--drivers/usb/gadget/u_ether.c21
1 files changed, 7 insertions, 14 deletions
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index c1b2d1c85..9b0cbbbe7 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -936,20 +936,13 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
req->length = length;
/* throttle high/super speed IRQ rate back slightly */
- if (gadget_is_dualspeed(dev->gadget) &&
- (dev->gadget->speed == USB_SPEED_HIGH ||
- dev->gadget->speed == USB_SPEED_SUPER)) {
- dev->tx_qlen++;
- if (dev->tx_qlen == (qmult/2)) {
- req->no_interrupt = 0;
- dev->tx_qlen = 0;
- } else {
- req->no_interrupt = 1;
- }
- } else {
- req->no_interrupt = 0;
- }
- rndis_test_tx_usb_out ++ ;
+ if (gadget_is_dualspeed(dev->gadget))
+ req->no_interrupt = (((dev->gadget->speed == USB_SPEED_HIGH ||
+ dev->gadget->speed == USB_SPEED_SUPER)) &&
+ !list_empty(&dev->tx_reqs))
+ ? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+ : 0;
+
retval = usb_ep_queue(in, req, GFP_ATOMIC);
switch (retval) {
default: