diff options
Diffstat (limited to 'target/linux/generic')
-rw-r--r-- | target/linux/generic/patches-3.10/140-revert_usb_unbind_interfaces.patch | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/target/linux/generic/patches-3.10/140-revert_usb_unbind_interfaces.patch b/target/linux/generic/patches-3.10/140-revert_usb_unbind_interfaces.patch new file mode 100644 index 0000000000..aa1ccb31ed --- /dev/null +++ b/target/linux/generic/patches-3.10/140-revert_usb_unbind_interfaces.patch @@ -0,0 +1,206 @@ +commit 032f44791457d9aa50c6a194a2d475f07e311afd +Author: Felix Fietkau <nbd@openwrt.org> +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); |