From: Kevin Cernekee Date: Thu, 9 Aug 2012 08:23:52 +0000 (+0300) Subject: usb: gadget: udc-core: Race between disconnect/unbind and setup X-Git-Tag: v3.7-rc1~171^2~141^2~53 X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=974e9323deefbab923d7aa8f0e4bcf9066c2ec97;p=~emulex%2Finfiniband.git usb: gadget: udc-core: Race between disconnect/unbind and setup usb_gadget_remove_driver() runs through a four-step sequence to shut down the gadget driver. For the case of a composite gadget + at91 UDC, this would look like: udc->driver->disconnect(udc->gadget); // composite_disconnect() usb_gadget_disconnect(udc->gadget); // at91_pullup(gadget, 0) udc->driver->unbind(udc->gadget); // composite_unbind() usb_gadget_udc_stop(udc->gadget, udc->driver); // at91_stop() The UDC driver can receive SETUP packets from the host up until the point when usb_gadget_disconnect() returns. On rare occasions, the gadget driver may see this sequence: udc->driver->disconnect(udc->gadget); // composite_disconnect() udc->driver->setup(udc->gadget, &ctrl); // composite_setup() udc->driver->unbind(udc->gadget); // composite_unbind() Some gadget drivers, such as composite, assume this will never happen and crash as a result. The fix is to quiesce the UDC hardware (via usb_gadget_disconnect) before running the gadget driver through the disconnect/unbind sequence. Reviewed-by: Peter Chen Signed-off-by: Kevin Cernekee Signed-off-by: Felipe Balbi --- diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index e5e44f8cde9..bae243c2314 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -262,8 +262,8 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); if (udc_is_newstyle(udc)) { - udc->driver->disconnect(udc->gadget); usb_gadget_disconnect(udc->gadget); + udc->driver->disconnect(udc->gadget); udc->driver->unbind(udc->gadget); usb_gadget_udc_stop(udc->gadget, udc->driver); } else {