Despite the needs_binding flag, the interface rebind was never done for the PM runtime resume. This patch fixes this issue by triggering the rebind in usb runtime resume. The rebind procedure needs to be called with the device lock. However, depending the call path (remote wakeup, local resume), the device lock may or may not already be held in usb runtime resume. So, use a work queue to take the lock unconditionally. Signed-off-by: Loic Poulain <loic.poulain@xxxxxxxxx> --- drivers/usb/core/driver.c | 12 ++++++++++++ drivers/usb/core/usb.c | 14 ++++++++++++++ include/linux/usb.h | 2 ++ 3 files changed, 28 insertions(+) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 888881e..b8d4f38 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1834,11 +1834,23 @@ int usb_runtime_resume(struct device *dev) { struct usb_device *udev = to_usb_device(dev); int status; + struct usb_interface *intf; + int i; /* Runtime resume for a USB device means resuming both the device * and all its interfaces. */ status = usb_resume_both(udev, PMSG_AUTO_RESUME); + + /* Schedule a safe device locked rebind if necessary */ + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + intf = udev->actconfig->interface[i]; + if (intf->needs_binding) { + schedule_work(&udev->rebind_ws); + break; + } + } + return status; } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 4d11449..9ec90a3 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -265,6 +265,7 @@ static void usb_release_dev(struct device *dev) udev = to_usb_device(dev); hcd = bus_to_hcd(udev->bus); + cancel_work_sync(&udev->rebind_ws); usb_destroy_configuration(udev); usb_release_bos_descriptor(udev); usb_put_hcd(hcd); @@ -386,6 +387,17 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus) return hcd->wireless; } +/* Internal function to queue device's interfaces rebind */ +static void usb_queue_rebind_interfaces(struct work_struct *ws) +{ + int rc; + struct usb_device *udev = + container_of(ws, struct usb_device, rebind_ws); + + usb_lock_device(udev); + usb_unbind_and_rebind_marked_interfaces(udev); + usb_unlock_device(udev); +} /** * usb_alloc_dev - usb device constructor (usbcore-internal) @@ -487,6 +499,8 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, dev->parent = parent; INIT_LIST_HEAD(&dev->filelist); + INIT_WORK(&dev->rebind_ws, usb_queue_rebind_interfaces); + #ifdef CONFIG_PM pm_runtime_set_autosuspend_delay(&dev->dev, usb_autosuspend_delay * 1000); diff --git a/include/linux/usb.h b/include/linux/usb.h index 6b7ec37..dae32df 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -508,6 +508,7 @@ struct usb3_lpm_parameters { * to keep track of the number of functions that require USB 3.0 Link Power * Management to be disabled for this usb_device. This count should only * be manipulated by those functions, with the bandwidth_mutex is held. + * @rebind_ws: used for scheduling interface rebind with device lock * * Notes: * Usbcore drivers should not set usbdev->state directly. Instead use @@ -587,6 +588,7 @@ struct usb_device { struct usb3_lpm_parameters u1_params; struct usb3_lpm_parameters u2_params; unsigned lpm_disable_count; + struct work_struct rebind_ws; }; #define to_usb_device(d) container_of(d, struct usb_device, dev) -- 1.8.3.2 --------------------------------------------------------------------- Intel Corporation SAS (French simplified joint stock company) Registered headquarters: "Les Montalets"- 2, rue de Paris, 92196 Meudon Cedex, France Registration Number: 302 456 199 R.C.S. NANTERRE Capital: 4,572,000 Euros This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies. -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html