lkml.org 
[lkml]   [2012]   [Aug]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[ 38/46] usb: gadget: u_ether: fix kworker 100% CPU issue with still used interfaces in eth_stop
    Date
    From: Greg KH <gregkh@linuxfoundation.org>

    3.5-stable review patch. If anyone has any objections, please let me know.

    ------------------

    From: Michael Grzeschik <m.grzeschik@pengutronix.de>

    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():

    usb_ep_disable(link->in_ep);
    usb_ep_disable(link->out_ep);
    if (netif_carrier_ok(net)) {
    usb_ep_enable(link->in_ep);
    usb_ep_enable(link->out_ep);
    }

    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
    usb_ep_enable().

    Cc: Tatyana Brokhman <tlinder@codeaurora.org>
    Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
    Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/usb/gadget/u_ether.c | 6 ++++++
    1 file changed, 6 insertions(+)

    --- 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 *n
    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)
    link->close(link);
    @@ -682,10 +684,14 @@ static int eth_stop(struct net_device *n
    * 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;
    usb_ep_disable(link->in_ep);
    usb_ep_disable(link->out_ep);
    if (netif_carrier_ok(net)) {
    DBG(dev, "host still using in/out endpoints\n");
    + link->in_ep->desc = in;
    + link->out_ep->desc = out;
    usb_ep_enable(link->in_ep);
    usb_ep_enable(link->out_ep);
    }



    \
     
     \ /
      Last update: 2012-08-20 06:41    [W:0.031 / U:122.756 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site