From e30da71b23d609480eaa7ff7ccbdfa738eac2b20 Mon Sep 17 00:00:00 2001 From: Feng Mingli Date: Thu, 23 Feb 2017 19:47:28 +0800 Subject: [PATCH] USB: core: flush pending URBs for unusual USB3 core when disable device According to xHCI spec v1.1 section 6.4.5 TRB Completion Codes, the standard XHCI controller provide a TRB Completion Status 'USB Transaction Error' to asserted in the case where the host did not receive a valid response from the device, it's useful to handle pending URBs on the endpoint when the USB device is plugged out. Unfortunately, some SOCs USB 3.0 modules lose the ability to assert the 'USB Transaction Error' status when USB 3.0 device disconnect. This may cause the pending URBs unhandled, even lead to USB class driver stalled in waiting for URBs complete. This patch flush pending URBs in usb_disable_device() when USB 3.0 device disconnect, it will call xhci_urb_dequeue() -> xhci_queue_stop_endpoint() to cancel pending URBs and giveback URB status immediately. Change-Id: If8acac59bc1f2c10a41ee390ccbeb84b2e7743c1 Signed-off-by: Feng Mingli Signed-off-by: Frank Wang --- drivers/usb/core/message.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 0d3fd2083165..35b7ac967b4d 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1209,7 +1209,7 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf, */ void usb_disable_device(struct usb_device *dev, int skip_ep0) { - int i; + int i, j; struct usb_hcd *hcd = bus_to_hcd(dev->bus); /* getting rid of interfaces will disconnect @@ -1234,6 +1234,27 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) dev_dbg(&dev->dev, "unregistering interface %s\n", dev_name(&interface->dev)); remove_intf_ep_devs(interface); + + /* + * Some special SoCs (e.g. rk322xh) USB 3.0 module + * can't handle outstanding URBs by hardware when + * when USB 3.0 device disconnect, so we need to + * cancel all URBs pending on this device here. + * + * In addition, we just reuse the hub autosuspend + * quirk but not add a new quirk for this issue. + * Because it always occurs with autosuspend issue. + */ + if (hcd->self.root_hub->quirks & + USB_QUIRK_AUTO_SUSPEND) { + for (j = skip_ep0; j < 16; ++j) { + usb_hcd_flush_endpoint(dev, + dev->ep_out[j]); + usb_hcd_flush_endpoint(dev, + dev->ep_in[j]); + } + } + device_del(&interface->dev); }