Commit b42e8090 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: UDC: Implement udc_async_callbacks in net2280

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.
Acked-by: default avatarFelipe Balbi <balbi@kernel.org>
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Link: https://lore.kernel.org/r/20210520202200.GE1216852@rowland.harvard.eduSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 04145a03
...@@ -1617,6 +1617,7 @@ static struct usb_ep *net2280_match_ep(struct usb_gadget *_gadget, ...@@ -1617,6 +1617,7 @@ static struct usb_ep *net2280_match_ep(struct usb_gadget *_gadget,
static int net2280_start(struct usb_gadget *_gadget, static int net2280_start(struct usb_gadget *_gadget,
struct usb_gadget_driver *driver); struct usb_gadget_driver *driver);
static int net2280_stop(struct usb_gadget *_gadget); 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 = { static const struct usb_gadget_ops net2280_ops = {
.get_frame = net2280_get_frame, .get_frame = net2280_get_frame,
...@@ -1625,6 +1626,7 @@ static const struct usb_gadget_ops net2280_ops = { ...@@ -1625,6 +1626,7 @@ static const struct usb_gadget_ops net2280_ops = {
.pullup = net2280_pullup, .pullup = net2280_pullup,
.udc_start = net2280_start, .udc_start = net2280_start,
.udc_stop = net2280_stop, .udc_stop = net2280_stop,
.udc_async_callbacks = net2280_async_callbacks,
.match_ep = net2280_match_ep, .match_ep = net2280_match_ep,
}; };
...@@ -2472,7 +2474,7 @@ static void stop_activity(struct net2280 *dev, struct usb_gadget_driver *driver) ...@@ -2472,7 +2474,7 @@ static void stop_activity(struct net2280 *dev, struct usb_gadget_driver *driver)
nuke(&dev->ep[i]); nuke(&dev->ep[i]);
/* report disconnect; the driver is already quiesced */ /* report disconnect; the driver is already quiesced */
if (driver) { if (dev->async_callbacks && driver) {
spin_unlock(&dev->lock); spin_unlock(&dev->lock);
driver->disconnect(&dev->gadget); driver->disconnect(&dev->gadget);
spin_lock(&dev->lock); spin_lock(&dev->lock);
...@@ -2502,6 +2504,15 @@ static int net2280_stop(struct usb_gadget *_gadget) ...@@ -2502,6 +2504,15 @@ static int net2280_stop(struct usb_gadget *_gadget)
return 0; 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. /* handle ep0, ep-e, ep-f with 64 byte packets: packet per irq.
...@@ -3042,10 +3053,12 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev, ...@@ -3042,10 +3053,12 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
readl(&ep->cfg->ep_cfg)); readl(&ep->cfg->ep_cfg));
ep->responded = 0; ep->responded = 0;
if (dev->async_callbacks) {
spin_unlock(&dev->lock); spin_unlock(&dev->lock);
tmp = dev->driver->setup(&dev->gadget, &r); tmp = dev->driver->setup(&dev->gadget, &r);
spin_lock(&dev->lock); spin_lock(&dev->lock);
} }
}
do_stall3: do_stall3:
if (tmp < 0) { if (tmp < 0) {
ep_vdbg(dev, "req %02x.%02x protocol STALL; stat %d\n", ep_vdbg(dev, "req %02x.%02x protocol STALL; stat %d\n",
...@@ -3284,10 +3297,12 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat) ...@@ -3284,10 +3297,12 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
w_value, w_index, w_length, w_value, w_index, w_length,
readl(&ep->cfg->ep_cfg)); readl(&ep->cfg->ep_cfg));
ep->responded = 0; ep->responded = 0;
if (dev->async_callbacks) {
spin_unlock(&dev->lock); spin_unlock(&dev->lock);
tmp = dev->driver->setup(&dev->gadget, &u.r); tmp = dev->driver->setup(&dev->gadget, &u.r);
spin_lock(&dev->lock); spin_lock(&dev->lock);
} }
}
/* stall ep0 on error */ /* stall ep0 on error */
if (tmp < 0) { if (tmp < 0) {
...@@ -3391,14 +3406,14 @@ __acquires(dev->lock) ...@@ -3391,14 +3406,14 @@ __acquires(dev->lock)
if (disconnect || reset) { if (disconnect || reset) {
stop_activity(dev, dev->driver); stop_activity(dev, dev->driver);
ep0_start(dev); ep0_start(dev);
if (dev->async_callbacks) {
spin_unlock(&dev->lock); spin_unlock(&dev->lock);
if (reset) if (reset)
usb_gadget_udc_reset usb_gadget_udc_reset(&dev->gadget, dev->driver);
(&dev->gadget, dev->driver);
else else
(dev->driver->disconnect) (dev->driver->disconnect)(&dev->gadget);
(&dev->gadget);
spin_lock(&dev->lock); spin_lock(&dev->lock);
}
return; return;
} }
} }
...@@ -3419,12 +3434,12 @@ __acquires(dev->lock) ...@@ -3419,12 +3434,12 @@ __acquires(dev->lock)
writel(tmp, &dev->regs->irqstat1); writel(tmp, &dev->regs->irqstat1);
spin_unlock(&dev->lock); spin_unlock(&dev->lock);
if (stat & BIT(SUSPEND_REQUEST_INTERRUPT)) { if (stat & BIT(SUSPEND_REQUEST_INTERRUPT)) {
if (dev->driver->suspend) if (dev->async_callbacks && dev->driver->suspend)
dev->driver->suspend(&dev->gadget); dev->driver->suspend(&dev->gadget);
if (!enable_suspend) if (!enable_suspend)
stat &= ~BIT(SUSPEND_REQUEST_INTERRUPT); stat &= ~BIT(SUSPEND_REQUEST_INTERRUPT);
} else { } else {
if (dev->driver->resume) if (dev->async_callbacks && dev->driver->resume)
dev->driver->resume(&dev->gadget); dev->driver->resume(&dev->gadget);
/* at high speed, note erratum 0133 */ /* at high speed, note erratum 0133 */
} }
......
...@@ -162,6 +162,7 @@ struct net2280 { ...@@ -162,6 +162,7 @@ struct net2280 {
ltm_enable:1, ltm_enable:1,
wakeup_enable:1, wakeup_enable:1,
addressed_state:1, addressed_state:1,
async_callbacks:1,
bug7734_patched:1; bug7734_patched:1;
u16 chiprev; u16 chiprev;
int enhanced_mode; int enhanced_mode;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment