From: Chunfeng Yun Date: Wed, 9 Oct 2019 09:05:00 +0000 (+0800) Subject: usb: mtu3: fix race condition about delayed_status X-Git-Tag: v5.10.7~3801^2~113 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b1a71c9047639e0a05683b55d37ff1a5c9bbcd07;p=platform%2Fkernel%2Flinux-rpi.git usb: mtu3: fix race condition about delayed_status 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 Link: https://lore.kernel.org/r/1570611900-7112-2-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c index df3fd05..2be182b 100644 --- a/drivers/usb/mtu3/mtu3_gadget_ep0.c +++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c @@ -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);