[lkml]   [2012]   [Sep]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
Patch in this message
Subject[ 18/95] usb: gadget: u_ether: fix kworker 100% CPU issue with still used interfaces in eth_stop
3.2-stable review patch.  If anyone has any objections, please let me know.


From: Michael Grzeschik <>

commit b1b552a69b8805e7e338074a9e8b670b4a795218 upstream.

This patch fixes an issue introduced by patch:

72c973d usb: gadget: add usb_endpoint_descriptor to struct usb_ep

Without this patch we see a kworker taking 100% CPU, after this sequence:

- Connect gadget to a windows host
- load g_ether
- ifconfig up <ip>; ifconfig down; ifconfig up
- ping <windows host>

The "ifconfig down" results in calling eth_stop(), which will call
usb_ep_disable() and, if the carrier is still ok, usb_ep_enable():

if (netif_carrier_ok(net)) {

The ep should stay enabled, but will not, as ep_disable set the desc
pointer to NULL, therefore the subsequent ep_enable will fail. This leads
to permanent rescheduling of the eth_work() worker as usb_ep_queue()
(called by the worker) will fail due to the unconfigured endpoint.

We fix this issue by saving the ep descriptors and re-assign them before

Cc: Tatyana Brokhman <>
Signed-off-by: Michael Grzeschik <>
Signed-off-by: Marc Kleine-Budde <>
Signed-off-by: Greg Kroah-Hartman <>
Signed-off-by: Ben Hutchings <>
drivers/usb/gadget/u_ether.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 90e82e2..0e52309 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -669,6 +669,8 @@ static int eth_stop(struct net_device *net)
spin_lock_irqsave(&dev->lock, flags);
if (dev->port_usb) {
struct gether *link = dev->port_usb;
+ const struct usb_endpoint_descriptor *in;
+ const struct usb_endpoint_descriptor *out;

if (link->close)
@@ -682,10 +684,14 @@ static int eth_stop(struct net_device *net)
* their own pace; the network stack can handle old packets.
* For the moment we leave this here, since it works.
+ in = link->in_ep->desc;
+ out = link->out_ep->desc;
if (netif_carrier_ok(net)) {
DBG(dev, "host still using in/out endpoints\n");
+ link->in_ep->desc = in;
+ link->out_ep->desc = out;

 \ /
  Last update: 2012-09-10 02:41    [W:0.455 / U:34.868 seconds]
©2003-2018 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site