| From c8476fb855434c733099079063990e5bfa7ecad6 Mon Sep 17 00:00:00 2001 |
| From: Shawn Nematbakhsh <shawnn@chromium.org> |
| Date: Mon, 19 Aug 2013 10:36:13 -0700 |
| Subject: usb: xhci: Disable runtime PM suspend for quirky controllers |
| |
| From: Shawn Nematbakhsh <shawnn@chromium.org> |
| |
| commit c8476fb855434c733099079063990e5bfa7ecad6 upstream. |
| |
| If a USB controller with XHCI_RESET_ON_RESUME goes to runtime suspend, |
| a reset will be performed upon runtime resume. Any previously suspended |
| devices attached to the controller will be re-enumerated at this time. |
| This will cause problems, for example, if an open system call on the |
| device triggered the resume (the open call will fail). |
| |
| Note that this change is only relevant when persist_enabled is not set |
| for USB devices. |
| |
| This patch should be backported to kernels as old as 3.0, that |
| contain the commit c877b3b2ad5cb9d4fe523c5496185cc328ff3ae9 "xhci: Add |
| reset on resume quirk for asrock p67 host". |
| |
| Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org> |
| Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/host/xhci.c | 22 ++++++++++++++++++++++ |
| 1 file changed, 22 insertions(+) |
| |
| --- a/drivers/usb/host/xhci.c |
| +++ b/drivers/usb/host/xhci.c |
| @@ -3511,10 +3511,21 @@ void xhci_free_dev(struct usb_hcd *hcd, |
| { |
| struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
| struct xhci_virt_device *virt_dev; |
| + struct device *dev = hcd->self.controller; |
| unsigned long flags; |
| u32 state; |
| int i, ret; |
| |
| +#ifndef CONFIG_USB_DEFAULT_PERSIST |
| + /* |
| + * We called pm_runtime_get_noresume when the device was attached. |
| + * Decrement the counter here to allow controller to runtime suspend |
| + * if no devices remain. |
| + */ |
| + if (xhci->quirks & XHCI_RESET_ON_RESUME) |
| + pm_runtime_put_noidle(dev); |
| +#endif |
| + |
| ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__); |
| /* If the host is halted due to driver unload, we still need to free the |
| * device. |
| @@ -3586,6 +3597,7 @@ static int xhci_reserve_host_control_ep_ |
| int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) |
| { |
| struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
| + struct device *dev = hcd->self.controller; |
| unsigned long flags; |
| int timeleft; |
| int ret; |
| @@ -3638,6 +3650,16 @@ int xhci_alloc_dev(struct usb_hcd *hcd, |
| goto disable_slot; |
| } |
| udev->slot_id = xhci->slot_id; |
| + |
| +#ifndef CONFIG_USB_DEFAULT_PERSIST |
| + /* |
| + * If resetting upon resume, we can't put the controller into runtime |
| + * suspend if there is a device attached. |
| + */ |
| + if (xhci->quirks & XHCI_RESET_ON_RESUME) |
| + pm_runtime_get_noresume(dev); |
| +#endif |
| + |
| /* Is this a LS or FS device under a HS hub? */ |
| /* Hub or peripherial? */ |
| return 1; |