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

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.edu


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 04145a03
Loading
Loading
Loading
Loading
+32 −17
Original line number Diff line number Diff line
@@ -1617,6 +1617,7 @@ static struct usb_ep *net2280_match_ep(struct usb_gadget *_gadget,
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 net2280_ops = {
	.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 *dev, struct usb_gadget_driver *driver)
		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_gadget *_gadget)
	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,10 +3053,12 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
				readl(&ep->cfg->ep_cfg));

		ep->responded = 0;
		if (dev->async_callbacks) {
			spin_unlock(&dev->lock);
			tmp = dev->driver->setup(&dev->gadget, &r);
			spin_lock(&dev->lock);
		}
	}
do_stall3:
	if (tmp < 0) {
		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)
				w_value, w_index, w_length,
				readl(&ep->cfg->ep_cfg));
			ep->responded = 0;
			if (dev->async_callbacks) {
				spin_unlock(&dev->lock);
				tmp = dev->driver->setup(&dev->gadget, &u.r);
				spin_lock(&dev->lock);
			}
		}

		/* stall ep0 on error */
		if (tmp < 0) {
@@ -3391,14 +3406,14 @@ __acquires(dev->lock)
			if (disconnect || reset) {
				stop_activity(dev, dev->driver);
				ep0_start(dev);
				if (dev->async_callbacks) {
					spin_unlock(&dev->lock);
					if (reset)
					usb_gadget_udc_reset
						(&dev->gadget, dev->driver);
						usb_gadget_udc_reset(&dev->gadget, dev->driver);
					else
					(dev->driver->disconnect)
						(&dev->gadget);
						(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 */
		}
+1 −0
Original line number Diff line number Diff line
@@ -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;