usb: chipidea: udc: don't do hardware access if gadget has stopped
authorPeter Chen <peter.chen@nxp.com>
Tue, 20 Aug 2019 02:07:58 +0000 (02:07 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 6 Sep 2019 08:22:15 +0000 (10:22 +0200)
commita209827549da0724ad0b6a9dbdc6d4742d875ebb
treea56148f0991554bc5c24347c3d55858d20aad7aa
parent97bec7afb98f310f0757d96e564020d0d31b6e0c
usb: chipidea: udc: don't do hardware access if gadget has stopped

commit cbe85c88ce80fb92956a0793518d415864dcead8 upstream.

After _gadget_stop_activity is executed, we can consider the hardware
operation for gadget has finished, and the udc can be stopped and enter
low power mode. So, any later hardware operations (from usb_ep_ops APIs
or usb_gadget_ops APIs) should be considered invalid, any deinitializatons
has been covered at _gadget_stop_activity.

I meet this problem when I plug out usb cable from PC using mass_storage
gadget, my callstack like: vbus interrupt->.vbus_session->
composite_disconnect ->pm_runtime_put_sync(&_gadget->dev),
the composite_disconnect will call fsg_disable, but fsg_disable calls
usb_ep_disable using async way, there are register accesses for
usb_ep_disable. So sometimes, I get system hang due to visit register
without clock, sometimes not.

The Linux Kernel USB maintainer Alan Stern suggests this kinds of solution.
See: http://marc.info/?l=linux-usb&m=138541769810983&w=2.

Cc: <stable@vger.kernel.org> #v4.9+
Signed-off-by: Peter Chen <peter.chen@nxp.com>
Link: https://lore.kernel.org/r/20190820020503.27080-2-peter.chen@nxp.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/chipidea/udc.c