Browse Source

kernel: revert an upstream linux-stable commit that is causing usb regressions on some brcm47xx and ar71xx devices

Signed-off-by: Felix Fietkau <[email protected]>

SVN-Revision: 41554
Felix Fietkau 11 years ago
parent
commit
f98306bef4

+ 206 - 0
target/linux/generic/patches-3.10/140-revert_usb_unbind_interfaces.patch

@@ -0,0 +1,206 @@
+commit 032f44791457d9aa50c6a194a2d475f07e311afd
+Author: Felix Fietkau <[email protected]>
+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);