Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Felipe Balbi <balbi@kernel.org>
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Link: https://lore.kernel.org/r/20210520202200.GE1216852@rowland.harvard.edu
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
b42e8090 04145a03

+33 -17
+32 -17
drivers/usb/gadget/udc/net2280.c
··· 1617 1617 static int net2280_start(struct usb_gadget *_gadget, 1618 1618 struct usb_gadget_driver *driver); 1619 1619 static int net2280_stop(struct usb_gadget *_gadget); 1620 + static void net2280_async_callbacks(struct usb_gadget *_gadget, bool enable); 1620 1621 1621 1622 static const struct usb_gadget_ops net2280_ops = { 1622 1623 .get_frame = net2280_get_frame, ··· 1626 1625 .pullup = net2280_pullup, 1627 1626 .udc_start = net2280_start, 1628 1627 .udc_stop = net2280_stop, 1628 + .udc_async_callbacks = net2280_async_callbacks, 1629 1629 .match_ep = net2280_match_ep, 1630 1630 }; 1631 1631 ··· 2474 2472 nuke(&dev->ep[i]); 2475 2473 2476 2474 /* report disconnect; the driver is already quiesced */ 2477 - if (driver) { 2475 + if (dev->async_callbacks && driver) { 2478 2476 spin_unlock(&dev->lock); 2479 2477 driver->disconnect(&dev->gadget); 2480 2478 spin_lock(&dev->lock); ··· 2502 2500 dev->driver = NULL; 2503 2501 2504 2502 return 0; 2503 + } 2504 + 2505 + static void net2280_async_callbacks(struct usb_gadget *_gadget, bool enable) 2506 + { 2507 + struct net2280 *dev = container_of(_gadget, struct net2280, gadget); 2508 + 2509 + spin_lock_irq(&dev->lock); 2510 + dev->async_callbacks = enable; 2511 + spin_unlock_irq(&dev->lock); 2505 2512 } 2506 2513 2507 2514 /*-------------------------------------------------------------------------*/ ··· 3053 3042 readl(&ep->cfg->ep_cfg)); 3054 3043 3055 3044 ep->responded = 0; 3056 - spin_unlock(&dev->lock); 3057 - tmp = dev->driver->setup(&dev->gadget, &r); 3058 - spin_lock(&dev->lock); 3045 + if (dev->async_callbacks) { 3046 + spin_unlock(&dev->lock); 3047 + tmp = dev->driver->setup(&dev->gadget, &r); 3048 + spin_lock(&dev->lock); 3049 + } 3059 3050 } 3060 3051 do_stall3: 3061 3052 if (tmp < 0) { ··· 3297 3284 w_value, w_index, w_length, 3298 3285 readl(&ep->cfg->ep_cfg)); 3299 3286 ep->responded = 0; 3300 - spin_unlock(&dev->lock); 3301 - tmp = dev->driver->setup(&dev->gadget, &u.r); 3302 - spin_lock(&dev->lock); 3287 + if (dev->async_callbacks) { 3288 + spin_unlock(&dev->lock); 3289 + tmp = dev->driver->setup(&dev->gadget, &u.r); 3290 + spin_lock(&dev->lock); 3291 + } 3303 3292 } 3304 3293 3305 3294 /* stall ep0 on error */ ··· 3406 3391 if (disconnect || reset) { 3407 3392 stop_activity(dev, dev->driver); 3408 3393 ep0_start(dev); 3409 - spin_unlock(&dev->lock); 3410 - if (reset) 3411 - usb_gadget_udc_reset 3412 - (&dev->gadget, dev->driver); 3413 - else 3414 - (dev->driver->disconnect) 3415 - (&dev->gadget); 3416 - spin_lock(&dev->lock); 3394 + if (dev->async_callbacks) { 3395 + spin_unlock(&dev->lock); 3396 + if (reset) 3397 + usb_gadget_udc_reset(&dev->gadget, dev->driver); 3398 + else 3399 + (dev->driver->disconnect)(&dev->gadget); 3400 + spin_lock(&dev->lock); 3401 + } 3417 3402 return; 3418 3403 } 3419 3404 } ··· 3434 3419 writel(tmp, &dev->regs->irqstat1); 3435 3420 spin_unlock(&dev->lock); 3436 3421 if (stat & BIT(SUSPEND_REQUEST_INTERRUPT)) { 3437 - if (dev->driver->suspend) 3422 + if (dev->async_callbacks && dev->driver->suspend) 3438 3423 dev->driver->suspend(&dev->gadget); 3439 3424 if (!enable_suspend) 3440 3425 stat &= ~BIT(SUSPEND_REQUEST_INTERRUPT); 3441 3426 } else { 3442 - if (dev->driver->resume) 3427 + if (dev->async_callbacks && dev->driver->resume) 3443 3428 dev->driver->resume(&dev->gadget); 3444 3429 /* at high speed, note erratum 0133 */ 3445 3430 }
+1
drivers/usb/gadget/udc/net2280.h
··· 162 162 ltm_enable:1, 163 163 wakeup_enable:1, 164 164 addressed_state:1, 165 + async_callbacks:1, 165 166 bug7734_patched:1; 166 167 u16 chiprev; 167 168 int enhanced_mode;