kernel: revert an upstream linux-stable commit that is causing usb regressions on some brcm47xx and ar71xx devices
Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 41554master
parent
f9c04c8722
commit
f98306bef4
@ -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);
|
Loading…
Reference in new issue