From patchwork Thu May 20 20:21:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Stern X-Patchwork-Id: 12271349 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.3 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9048FC433ED for ; Thu, 20 May 2021 20:21:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 70D8B60FDC for ; Thu, 20 May 2021 20:21:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236045AbhETUXH (ORCPT ); Thu, 20 May 2021 16:23:07 -0400 Received: from netrider.rowland.org ([192.131.102.5]:55363 "HELO netrider.rowland.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S236062AbhETUXG (ORCPT ); Thu, 20 May 2021 16:23:06 -0400 Received: (qmail 1217337 invoked by uid 1000); 20 May 2021 16:21:44 -0400 Date: Thu, 20 May 2021 16:21:44 -0400 From: Alan Stern To: Felipe Balbi Cc: USB mailing list Subject: [PATCH 1/4] USB: UDC core: Add udc_async_callbacks gadget op Message-ID: <20210520202144.GC1216852@rowland.harvard.edu> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.10.1 (2018-07-13) Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org The Gadget API has a theoretical race when a gadget driver is unbound. Although the pull-up is turned off before the driver's ->unbind callback runs, if the USB cable were to be unplugged at just the wrong moment there would be nothing to prevent the UDC driver from invoking the ->disconnect callback after the unbind has finished. In theory, other asynchronous callbacks could also happen during the time before the UDC driver's udc_stop routine is called, and the gadget driver would not be prepared to handle any of them. We need a way to tell UDC drivers to stop issuing asynchronous (that is, ->suspend, ->resume, ->disconnect, ->reset, or ->setup) callbacks at some point after the pull-up has been turned off and before the ->unbind callback runs. This patch adds a new ->udc_async_callbacks callback to the usb_gadget_ops structure for precisely this purpose, and it adds the corresponding support to the UDC core. Later patches in this series add support for udc_async_callbacks to several UDC drivers. Signed-off-by: Alan Stern Acked-by: Felipe Balbi --- [as1956] drivers/usb/gadget/udc/core.c | 49 ++++++++++++++++++++++++++++++++++++++++++ include/linux/usb/gadget.h | 1 2 files changed, 50 insertions(+) Index: usb-devel/drivers/usb/gadget/udc/core.c =================================================================== --- usb-devel.orig/drivers/usb/gadget/udc/core.c +++ usb-devel/drivers/usb/gadget/udc/core.c @@ -1148,6 +1148,53 @@ static inline void usb_gadget_udc_set_sp } /** + * usb_gadget_enable_async_callbacks - tell usb device controller to enable asynchronous callbacks + * @udc: The UDC which should enable async callbacks + * + * This routine is used when binding gadget drivers. It undoes the effect + * of usb_gadget_disable_async_callbacks(); the UDC driver should enable IRQs + * (if necessary) and resume issuing callbacks. + * + * This routine will always be called in process context. + */ +static inline void usb_gadget_enable_async_callbacks(struct usb_udc *udc) +{ + struct usb_gadget *gadget = udc->gadget; + + if (gadget->ops->udc_async_callbacks) + gadget->ops->udc_async_callbacks(gadget, true); +} + +/** + * usb_gadget_disable_async_callbacks - tell usb device controller to disable asynchronous callbacks + * @udc: The UDC which should disable async callbacks + * + * This routine is used when unbinding gadget drivers. It prevents a race: + * The UDC driver doesn't know when the gadget driver's ->unbind callback + * runs, so unless it is told to disable asynchronous callbacks, it might + * issue a callback (such as ->disconnect) after the unbind has completed. + * + * After this function runs, the UDC driver must suppress all ->suspend, + * ->resume, ->disconnect, ->reset, and ->setup callbacks to the gadget driver + * until async callbacks are again enabled. A simple-minded but effective + * way to accomplish this is to tell the UDC hardware not to generate any + * more IRQs. + * + * Request completion callbacks must still be issued. However, it's okay + * to defer them until the request is cancelled, since the pull-up will be + * turned off during the time period when async callbacks are disabled. + * + * This routine will always be called in process context. + */ +static inline void usb_gadget_disable_async_callbacks(struct usb_udc *udc) +{ + struct usb_gadget *gadget = udc->gadget; + + if (gadget->ops->udc_async_callbacks) + gadget->ops->udc_async_callbacks(gadget, false); +} + +/** * usb_udc_release - release the usb_udc struct * @dev: the dev member within usb_udc * @@ -1361,6 +1408,7 @@ static void usb_gadget_remove_driver(str kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); usb_gadget_disconnect(udc->gadget); + usb_gadget_disable_async_callbacks(udc); if (udc->gadget->irq) synchronize_irq(udc->gadget->irq); udc->driver->unbind(udc->gadget); @@ -1442,6 +1490,7 @@ static int udc_bind_to_driver(struct usb driver->unbind(udc->gadget); goto err1; } + usb_gadget_enable_async_callbacks(udc); usb_udc_connect_control(udc); kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); Index: usb-devel/include/linux/usb/gadget.h =================================================================== --- usb-devel.orig/include/linux/usb/gadget.h +++ usb-devel/include/linux/usb/gadget.h @@ -325,6 +325,7 @@ struct usb_gadget_ops { void (*udc_set_speed)(struct usb_gadget *, enum usb_device_speed); void (*udc_set_ssp_rate)(struct usb_gadget *gadget, enum usb_ssp_rate rate); + void (*udc_async_callbacks)(struct usb_gadget *gadget, bool enable); struct usb_ep *(*match_ep)(struct usb_gadget *, struct usb_endpoint_descriptor *, struct usb_ss_ep_comp_descriptor *); From patchwork Thu May 20 20:21:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Stern X-Patchwork-Id: 12271351 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.3 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C837C433ED for ; Thu, 20 May 2021 20:21:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5FFCB60FDC for ; Thu, 20 May 2021 20:21:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236069AbhETUXQ (ORCPT ); Thu, 20 May 2021 16:23:16 -0400 Received: from netrider.rowland.org ([192.131.102.5]:54383 "HELO netrider.rowland.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S236062AbhETUXP (ORCPT ); Thu, 20 May 2021 16:23:15 -0400 Received: (qmail 1217366 invoked by uid 1000); 20 May 2021 16:21:52 -0400 Date: Thu, 20 May 2021 16:21:52 -0400 From: Alan Stern To: Felipe Balbi Cc: USB mailing list Subject: [PATCH 2/4] USB: UDC: Implement udc_async_callbacks in dummy-hcd Message-ID: <20210520202152.GD1216852@rowland.harvard.edu> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.10.1 (2018-07-13) Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org This patch adds a udc_async_callbacks handler to the dummy-hcd UDC driver, which will prevent a theoretical race during gadget unbinding. The implementation is simple, since dummy-hcd already has a flag to keep track of whether emulated IRQs are enabled. All the handler has to do is store the enable value in the flag, and avoid setting the flag prematurely. Signed-off-by: Alan Stern Acked-by: Felipe Balbi --- [as1957] drivers/usb/gadget/udc/dummy_hcd.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) Index: usb-devel/drivers/usb/gadget/udc/dummy_hcd.c =================================================================== --- usb-devel.orig/drivers/usb/gadget/udc/dummy_hcd.c +++ usb-devel/drivers/usb/gadget/udc/dummy_hcd.c @@ -919,6 +919,15 @@ static void dummy_udc_set_speed(struct u dummy_udc_update_ep0(dum); } +static void dummy_udc_async_callbacks(struct usb_gadget *_gadget, bool enable) +{ + struct dummy *dum = gadget_dev_to_dummy(&_gadget->dev); + + spin_lock_irq(&dum->lock); + dum->ints_enabled = enable; + spin_unlock_irq(&dum->lock); +} + static int dummy_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); static int dummy_udc_stop(struct usb_gadget *g); @@ -931,6 +940,7 @@ static const struct usb_gadget_ops dummy .udc_start = dummy_udc_start, .udc_stop = dummy_udc_stop, .udc_set_speed = dummy_udc_set_speed, + .udc_async_callbacks = dummy_udc_async_callbacks, }; /*-------------------------------------------------------------------------*/ @@ -990,7 +1000,6 @@ static int dummy_udc_start(struct usb_ga spin_lock_irq(&dum->lock); dum->devstatus = 0; dum->driver = driver; - dum->ints_enabled = 1; spin_unlock_irq(&dum->lock); return 0; From patchwork Thu May 20 20:22:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Stern X-Patchwork-Id: 12271353 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.3 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1A0B3C433ED for ; Thu, 20 May 2021 20:22:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F1C366135C for ; Thu, 20 May 2021 20:22:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236192AbhETUXY (ORCPT ); Thu, 20 May 2021 16:23:24 -0400 Received: from netrider.rowland.org ([192.131.102.5]:41495 "HELO netrider.rowland.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S236062AbhETUXW (ORCPT ); Thu, 20 May 2021 16:23:22 -0400 Received: (qmail 1217378 invoked by uid 1000); 20 May 2021 16:22:00 -0400 Date: Thu, 20 May 2021 16:22:00 -0400 From: Alan Stern To: Felipe Balbi Cc: USB mailing list Subject: [PATCH 3/4] USB: UDC: Implement udc_async_callbacks in net2280 Message-ID: <20210520202200.GE1216852@rowland.harvard.edu> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.10.1 (2018-07-13) Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org This patch adds a udc_async_callbacks handler to the net2280 UDC driver, which will prevent a theoretical race during gadget unbinding. The net2280 driver is sufficiently complicated that I didn't want to mess around with IRQ settings. Instead, the patch simply adds a new flag to control async callbacks, and checks the flag before issuing any of them. Signed-off-by: Alan Stern Acked-by: Felipe Balbi --- [as1958] drivers/usb/gadget/udc/net2280.c | 49 +++++++++++++++++++++++++-------------- drivers/usb/gadget/udc/net2280.h | 1 2 files changed, 33 insertions(+), 17 deletions(-) Index: usb-devel/drivers/usb/gadget/udc/net2280.c =================================================================== --- usb-devel.orig/drivers/usb/gadget/udc/net2280.c +++ usb-devel/drivers/usb/gadget/udc/net2280.c @@ -1617,6 +1617,7 @@ static struct usb_ep *net2280_match_ep(s static int net2280_start(struct usb_gadget *_gadget, struct usb_gadget_driver *driver); static int net2280_stop(struct usb_gadget *_gadget); +static void net2280_async_callbacks(struct usb_gadget *_gadget, bool enable); static const struct usb_gadget_ops net2280_ops = { .get_frame = net2280_get_frame, @@ -1625,6 +1626,7 @@ static const struct usb_gadget_ops net22 .pullup = net2280_pullup, .udc_start = net2280_start, .udc_stop = net2280_stop, + .udc_async_callbacks = net2280_async_callbacks, .match_ep = net2280_match_ep, }; @@ -2472,7 +2474,7 @@ static void stop_activity(struct net2280 nuke(&dev->ep[i]); /* report disconnect; the driver is already quiesced */ - if (driver) { + if (dev->async_callbacks && driver) { spin_unlock(&dev->lock); driver->disconnect(&dev->gadget); spin_lock(&dev->lock); @@ -2502,6 +2504,15 @@ static int net2280_stop(struct usb_gadge return 0; } +static void net2280_async_callbacks(struct usb_gadget *_gadget, bool enable) +{ + struct net2280 *dev = container_of(_gadget, struct net2280, gadget); + + spin_lock_irq(&dev->lock); + dev->async_callbacks = enable; + spin_unlock_irq(&dev->lock); +} + /*-------------------------------------------------------------------------*/ /* handle ep0, ep-e, ep-f with 64 byte packets: packet per irq. @@ -3042,9 +3053,11 @@ usb3_delegate: readl(&ep->cfg->ep_cfg)); ep->responded = 0; - spin_unlock(&dev->lock); - tmp = dev->driver->setup(&dev->gadget, &r); - spin_lock(&dev->lock); + if (dev->async_callbacks) { + spin_unlock(&dev->lock); + tmp = dev->driver->setup(&dev->gadget, &r); + spin_lock(&dev->lock); + } } do_stall3: if (tmp < 0) { @@ -3284,9 +3297,11 @@ delegate: w_value, w_index, w_length, readl(&ep->cfg->ep_cfg)); ep->responded = 0; - spin_unlock(&dev->lock); - tmp = dev->driver->setup(&dev->gadget, &u.r); - spin_lock(&dev->lock); + if (dev->async_callbacks) { + spin_unlock(&dev->lock); + tmp = dev->driver->setup(&dev->gadget, &u.r); + spin_lock(&dev->lock); + } } /* stall ep0 on error */ @@ -3391,14 +3406,14 @@ __acquires(dev->lock) if (disconnect || reset) { stop_activity(dev, dev->driver); ep0_start(dev); - spin_unlock(&dev->lock); - if (reset) - usb_gadget_udc_reset - (&dev->gadget, dev->driver); - else - (dev->driver->disconnect) - (&dev->gadget); - spin_lock(&dev->lock); + if (dev->async_callbacks) { + spin_unlock(&dev->lock); + if (reset) + usb_gadget_udc_reset(&dev->gadget, dev->driver); + else + (dev->driver->disconnect)(&dev->gadget); + spin_lock(&dev->lock); + } return; } } @@ -3419,12 +3434,12 @@ __acquires(dev->lock) writel(tmp, &dev->regs->irqstat1); spin_unlock(&dev->lock); if (stat & BIT(SUSPEND_REQUEST_INTERRUPT)) { - if (dev->driver->suspend) + if (dev->async_callbacks && dev->driver->suspend) dev->driver->suspend(&dev->gadget); if (!enable_suspend) stat &= ~BIT(SUSPEND_REQUEST_INTERRUPT); } else { - if (dev->driver->resume) + if (dev->async_callbacks && dev->driver->resume) dev->driver->resume(&dev->gadget); /* at high speed, note erratum 0133 */ } Index: usb-devel/drivers/usb/gadget/udc/net2280.h =================================================================== --- usb-devel.orig/drivers/usb/gadget/udc/net2280.h +++ usb-devel/drivers/usb/gadget/udc/net2280.h @@ -162,6 +162,7 @@ struct net2280 { ltm_enable:1, wakeup_enable:1, addressed_state:1, + async_callbacks:1, bug7734_patched:1; u16 chiprev; int enhanced_mode; From patchwork Thu May 20 20:22:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Stern X-Patchwork-Id: 12271355 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.5 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C9348C433B4 for ; Thu, 20 May 2021 20:22:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A9F1B6135B for ; Thu, 20 May 2021 20:22:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236142AbhETUX3 (ORCPT ); Thu, 20 May 2021 16:23:29 -0400 Received: from netrider.rowland.org ([192.131.102.5]:33487 "HELO netrider.rowland.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S235955AbhETUX3 (ORCPT ); Thu, 20 May 2021 16:23:29 -0400 Received: (qmail 1217395 invoked by uid 1000); 20 May 2021 16:22:06 -0400 Date: Thu, 20 May 2021 16:22:06 -0400 From: Alan Stern To: Felipe Balbi Cc: USB mailing list Subject: [PATCH 4/4] USB: UDC: Implement udc_async_callbacks in net2272 Message-ID: <20210520202206.GF1216852@rowland.harvard.edu> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.10.1 (2018-07-13) Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org This patch adds a udc_async_callbacks handler to the net2272 UDC driver, which will prevent a theoretical race during gadget unbinding. The net2272 driver is sufficiently complicated that I didn't want to mess around with IRQ settings. Instead, the patch simply adds a new flag to control async callbacks, and checks the flag before issuing any of them. Signed-off-by: Alan Stern Acked-by: Felipe Balbi --- [as1959] drivers/usb/gadget/udc/net2272.c | 41 +++++++++++++++++++++++++-------------- drivers/usb/gadget/udc/net2272.h | 1 2 files changed, 28 insertions(+), 14 deletions(-) Index: usb-devel/drivers/usb/gadget/udc/net2272.c =================================================================== --- usb-devel.orig/drivers/usb/gadget/udc/net2272.c +++ usb-devel/drivers/usb/gadget/udc/net2272.c @@ -1149,6 +1149,7 @@ net2272_pullup(struct usb_gadget *_gadge static int net2272_start(struct usb_gadget *_gadget, struct usb_gadget_driver *driver); static int net2272_stop(struct usb_gadget *_gadget); +static void net2272_async_callbacks(struct usb_gadget *_gadget, bool enable); static const struct usb_gadget_ops net2272_ops = { .get_frame = net2272_get_frame, @@ -1157,6 +1158,7 @@ static const struct usb_gadget_ops net22 .pullup = net2272_pullup, .udc_start = net2272_start, .udc_stop = net2272_stop, + .udc_async_callbacks = net2272_async_callbacks, }; /*---------------------------------------------------------------------------*/ @@ -1475,7 +1477,7 @@ stop_activity(struct net2272 *dev, struc net2272_dequeue_all(&dev->ep[i]); /* report disconnect; the driver is already quiesced */ - if (driver) { + if (dev->async_callbacks && driver) { spin_unlock(&dev->lock); driver->disconnect(&dev->gadget); spin_lock(&dev->lock); @@ -1500,6 +1502,15 @@ static int net2272_stop(struct usb_gadge return 0; } +static void net2272_async_callbacks(struct usb_gadget *_gadget, bool enable) +{ + struct net2272 *dev = container_of(_gadget, struct net2272, gadget); + + spin_lock_irq(&dev->lock); + dev->async_callbacks = enable; + spin_unlock_irq(&dev->lock); +} + /*---------------------------------------------------------------------------*/ /* handle ep-a/ep-b dma completions */ static void @@ -1909,9 +1920,11 @@ net2272_handle_stat0_irqs(struct net2272 u.r.bRequestType, u.r.bRequest, u.r.wValue, u.r.wIndex, net2272_ep_read(ep, EP_CFG)); - spin_unlock(&dev->lock); - tmp = dev->driver->setup(&dev->gadget, &u.r); - spin_lock(&dev->lock); + if (dev->async_callbacks) { + spin_unlock(&dev->lock); + tmp = dev->driver->setup(&dev->gadget, &u.r); + spin_lock(&dev->lock); + } } /* stall ep0 on error */ @@ -1993,14 +2006,14 @@ net2272_handle_stat1_irqs(struct net2272 if (disconnect || reset) { stop_activity(dev, dev->driver); net2272_ep0_start(dev); - spin_unlock(&dev->lock); - if (reset) - usb_gadget_udc_reset - (&dev->gadget, dev->driver); - else - (dev->driver->disconnect) - (&dev->gadget); - spin_lock(&dev->lock); + if (dev->async_callbacks) { + spin_unlock(&dev->lock); + if (reset) + usb_gadget_udc_reset(&dev->gadget, dev->driver); + else + (dev->driver->disconnect)(&dev->gadget); + spin_lock(&dev->lock); + } return; } } @@ -2014,14 +2027,14 @@ net2272_handle_stat1_irqs(struct net2272 if (stat & tmp) { net2272_write(dev, IRQSTAT1, tmp); if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) { - if (dev->driver->suspend) + if (dev->async_callbacks && dev->driver->suspend) dev->driver->suspend(&dev->gadget); if (!enable_suspend) { stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT); dev_dbg(dev->dev, "Suspend disabled, ignoring\n"); } } else { - if (dev->driver->resume) + if (dev->async_callbacks && dev->driver->resume) dev->driver->resume(&dev->gadget); } stat &= ~tmp; Index: usb-devel/drivers/usb/gadget/udc/net2272.h =================================================================== --- usb-devel.orig/drivers/usb/gadget/udc/net2272.h +++ usb-devel/drivers/usb/gadget/udc/net2272.h @@ -442,6 +442,7 @@ struct net2272 { softconnect:1, wakeup:1, added:1, + async_callbacks:1, dma_eot_polarity:1, dma_dack_polarity:1, dma_dreq_polarity:1,