usb: mtu3: fix race condition about delayed_status
authorChunfeng Yun <chunfeng.yun@mediatek.com>
Wed, 9 Oct 2019 09:05:00 +0000 (17:05 +0800)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Wed, 23 Oct 2019 06:26:29 +0000 (09:26 +0300)
usb_composite_setup_continue() may be called before composite_setup()
return USB_GADGET_DELAYED_STATUS, then the controller driver will
delay status stage after composite_setup() finish, but the class driver
don't ask the controller to continue delayed status anymore, this will
cause control transfer timeout.

happens when use mass storage (also enabled other class driver):

cpu1:                               cpu2
handle_setup(SET_CONFIG) //gadget driver
  unlock (g->lock)
  gadget_driver->setup()
    composite_setup()
      lock(cdev->lock)
        set_config()
          fsg_set_alt() // maybe some times due to many class are enabled
            raise FSG_STATE_CONFIG_CHANGE
            return USB_GADGET_DELAYED_STATUS
                                    handle_exception()
                                    usb_composite_setup_continue()
      unlock(cdev->lock)
                                      lock(cdev->lock)
                                        ep0_queue()
                                          lock (g->lock)
                                          //no delayed status, nothing todo
                                          unlock (g->lock)
                                      unlock(cdev->lock)
    return USB_GADGET_DELAYED_STATUS // composite_setup
  lock (g->lock)
get USB_GADGET_DELAYED_STATUS //handle_setup [1]

Try to fix the race condition as following:
After the driver gets USB_GADGET_DELAYED_STATUS at [1], if we find
there is a usb_request in ep0 request list, it means composite already
asked us to continue delayed status by usb_composite_setup_continue(),
so we skip request about delayed_status by composite_setup() and still
do status stage.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
drivers/usb/mtu3/mtu3_gadget_ep0.c

index df3fd05..2be182b 100644 (file)
@@ -671,8 +671,16 @@ finish:
        if (mtu->test_mode) {
                ;       /* nothing to do */
        } else if (handled == USB_GADGET_DELAYED_STATUS) {
-               /* handle the delay STATUS phase till receive ep_queue on ep0 */
-               mtu->delayed_status = true;
+
+               mreq = next_ep0_request(mtu);
+               if (mreq) {
+                       /* already asked us to continue delayed status */
+                       ep0_do_status_stage(mtu);
+                       ep0_req_giveback(mtu, &mreq->request);
+               } else {
+                       /* do delayed STATUS stage till receive ep0_queue */
+                       mtu->delayed_status = true;
+               }
        } else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */
 
                ep0_do_status_stage(mtu);