commit 032f44791457d9aa50c6a194a2d475f07e311afd Author: Felix Fietkau Date: Wed Jul 9 12:08:23 2014 +0200 Revert "USB: unbind all interfaces before rebinding any" This reverts commit 59f0103d74e4a32cbaa054d5011ea287fcfb83e4. The commit has been found to cause USB regressions on AR933x and BCM4705. --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -953,7 +953,8 @@ EXPORT_SYMBOL_GPL(usb_deregister); * it doesn't support pre_reset/post_reset/reset_resume or * because it doesn't support suspend/resume. * - * The caller must hold @intf's device's lock, but not @intf's lock. + * The caller must hold @intf's device's lock, but not its pm_mutex + * and not @intf->dev.sem. */ void usb_forced_unbind_intf(struct usb_interface *intf) { @@ -966,37 +967,16 @@ void usb_forced_unbind_intf(struct usb_i intf->needs_binding = 1; } -/* - * Unbind drivers for @udev's marked interfaces. These interfaces have - * the needs_binding flag set, for example by usb_resume_interface(). - * - * The caller must hold @udev's device lock. - */ -static void unbind_marked_interfaces(struct usb_device *udev) -{ - struct usb_host_config *config; - int i; - struct usb_interface *intf; - - config = udev->actconfig; - if (config) { - for (i = 0; i < config->desc.bNumInterfaces; ++i) { - intf = config->interface[i]; - if (intf->dev.driver && intf->needs_binding) - usb_forced_unbind_intf(intf); - } - } -} - /* Delayed forced unbinding of a USB interface driver and scan * for rebinding. * - * The caller must hold @intf's device's lock, but not @intf's lock. + * The caller must hold @intf's device's lock, but not its pm_mutex + * and not @intf->dev.sem. * * Note: Rebinds will be skipped if a system sleep transition is in * progress and the PM "complete" callback hasn't occurred yet. */ -static void usb_rebind_intf(struct usb_interface *intf) +void usb_rebind_intf(struct usb_interface *intf) { int rc; @@ -1013,66 +993,68 @@ static void usb_rebind_intf(struct usb_i } } -/* - * Rebind drivers to @udev's marked interfaces. These interfaces have - * the needs_binding flag set. +#ifdef CONFIG_PM + +/* Unbind drivers for @udev's interfaces that don't support suspend/resume + * There is no check for reset_resume here because it can be determined + * only during resume whether reset_resume is needed. * * The caller must hold @udev's device lock. */ -static void rebind_marked_interfaces(struct usb_device *udev) +static void unbind_no_pm_drivers_interfaces(struct usb_device *udev) { struct usb_host_config *config; int i; struct usb_interface *intf; + struct usb_driver *drv; config = udev->actconfig; if (config) { for (i = 0; i < config->desc.bNumInterfaces; ++i) { intf = config->interface[i]; - if (intf->needs_binding) - usb_rebind_intf(intf); + + if (intf->dev.driver) { + drv = to_usb_driver(intf->dev.driver); + if (!drv->suspend || !drv->resume) + usb_forced_unbind_intf(intf); + } } } } -/* - * Unbind all of @udev's marked interfaces and then rebind all of them. - * This ordering is necessary because some drivers claim several interfaces - * when they are first probed. +/* Unbind drivers for @udev's interfaces that failed to support reset-resume. + * These interfaces have the needs_binding flag set by usb_resume_interface(). * * The caller must hold @udev's device lock. */ -void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev) +static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev) { - unbind_marked_interfaces(udev); - rebind_marked_interfaces(udev); -} + struct usb_host_config *config; + int i; + struct usb_interface *intf; -#ifdef CONFIG_PM + config = udev->actconfig; + if (config) { + for (i = 0; i < config->desc.bNumInterfaces; ++i) { + intf = config->interface[i]; + if (intf->dev.driver && intf->needs_binding) + usb_forced_unbind_intf(intf); + } + } +} -/* Unbind drivers for @udev's interfaces that don't support suspend/resume - * There is no check for reset_resume here because it can be determined - * only during resume whether reset_resume is needed. - * - * The caller must hold @udev's device lock. - */ -static void unbind_no_pm_drivers_interfaces(struct usb_device *udev) +static void do_rebind_interfaces(struct usb_device *udev) { struct usb_host_config *config; int i; struct usb_interface *intf; - struct usb_driver *drv; config = udev->actconfig; if (config) { for (i = 0; i < config->desc.bNumInterfaces; ++i) { intf = config->interface[i]; - - if (intf->dev.driver) { - drv = to_usb_driver(intf->dev.driver); - if (!drv->suspend || !drv->resume) - usb_forced_unbind_intf(intf); - } + if (intf->needs_binding) + usb_rebind_intf(intf); } } } @@ -1397,7 +1379,7 @@ int usb_resume_complete(struct device *d * whose needs_binding flag is set */ if (udev->state != USB_STATE_NOTATTACHED) - rebind_marked_interfaces(udev); + do_rebind_interfaces(udev); return 0; } @@ -1419,7 +1401,7 @@ int usb_resume(struct device *dev, pm_me pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); - unbind_marked_interfaces(udev); + unbind_no_reset_resume_drivers_interfaces(udev); } /* Avoid PM error messages for devices disconnected while suspended --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -5263,11 +5263,10 @@ int usb_reset_device(struct usb_device * else if (cintf->condition == USB_INTERFACE_BOUND) rebind = 1; - if (rebind) - cintf->needs_binding = 1; } + if (ret == 0 && rebind) + usb_rebind_intf(cintf); } - usb_unbind_and_rebind_marked_interfaces(udev); } usb_autosuspend_device(udev); --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -55,7 +55,7 @@ extern int usb_match_one_id_intf(struct extern int usb_match_device(struct usb_device *dev, const struct usb_device_id *id); extern void usb_forced_unbind_intf(struct usb_interface *intf); -extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev); +extern void usb_rebind_intf(struct usb_interface *intf); extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port, struct dev_state *owner);