USB: UDC: Implement udc_async_callbacks in net2272
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. Acked-by: Felipe Balbi <balbi@kernel.org> Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/20210520202206.GF1216852@rowland.harvard.edu Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
b42e8090ba
commit
87191ca9f9
@ -1150,6 +1150,7 @@ net2272_pullup(struct usb_gadget *_gadget, int is_on)
|
||||
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,
|
||||
@ -1158,6 +1159,7 @@ static const struct usb_gadget_ops net2272_ops = {
|
||||
.pullup = net2272_pullup,
|
||||
.udc_start = net2272_start,
|
||||
.udc_stop = net2272_stop,
|
||||
.udc_async_callbacks = net2272_async_callbacks,
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
@ -1476,7 +1478,7 @@ stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver)
|
||||
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);
|
||||
@ -1501,6 +1503,15 @@ static int net2272_stop(struct usb_gadget *_gadget)
|
||||
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
|
||||
@ -1910,9 +1921,11 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
|
||||
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 */
|
||||
@ -1994,14 +2007,14 @@ net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat)
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -2015,14 +2028,14 @@ net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat)
|
||||
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;
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user