[RFC PATCH 2/2] usb: core: hub: avoid reset hub during probe

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When start probe hub, during INIT, INTT2, INIT3 stage, when link state
change to inactive, currently it will reset the device, maybe it will
trigger warning in usb_submit_urb() due to urb->hcpriv is still active.

Add a flag name init_stage to avoid reset the device.

Signed-off-by: Linyu Yuan <quic_linyyuan@xxxxxxxxxxx>
---
 drivers/usb/core/hub.c | 20 +++++++++++++++++++-
 drivers/usb/core/hub.h |  1 +
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 97a0f8f..3cb1137 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1290,6 +1290,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
 	if (type == HUB_INIT2 || type == HUB_INIT3) {
 		/* Allow autosuspend if it was suppressed */
  disconnected:
+		hub->init_stage = 0;
 		usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
 		device_unlock(&hdev->dev);
 	}
@@ -1872,6 +1873,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	kref_init(&hub->kref);
 	hub->intfdev = &intf->dev;
 	hub->hdev = hdev;
+	hub->init_stage = 1;
 	INIT_DELAYED_WORK(&hub->leds, led_work);
 	INIT_DELAYED_WORK(&hub->init_work, NULL);
 	INIT_WORK(&hub->events, hub_event);
@@ -5587,6 +5589,21 @@ static void port_over_current_notify(struct usb_port *port_dev)
 	kfree(port_dev_path);
 }
 
+static bool port_child_avoid_reset(struct usb_device *udev)
+{
+	struct usb_hub *hub;
+
+	if (udev->descriptor.bDeviceClass == USB_CLASS_HUB &&
+	    udev->state == USB_STATE_CONFIGURED) {
+		hub = usb_get_intfdata(udev->actconfig->interface[0]);
+
+		if (hub && hub->init_stage)
+			return true;
+	}
+
+	return false;
+}
+
 static void port_event(struct usb_hub *hub, int port1)
 		__must_hold(&port_dev->status_lock)
 {
@@ -5699,7 +5716,8 @@ static void port_event(struct usb_hub *hub, int port1)
 			dev_dbg(&port_dev->dev, "do warm reset, full device\n");
 			usb_unlock_port(port_dev);
 			usb_lock_device(udev);
-			usb_reset_device(udev);
+			if (!port_child_avoid_reset(udev))
+				usb_reset_device(udev);
 			usb_unlock_device(udev);
 			usb_lock_port(port_dev);
 			connect_change = 0;
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index e238335..040524f 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -66,6 +66,7 @@ struct usb_hub {
 	unsigned		quirk_check_port_auto_suspend:1;
 
 	unsigned		has_indicators:1;
+	unsigned		init_stage:1;
 	u8			indicator[USB_MAXCHILDREN];
 	struct delayed_work	leds;
 	struct delayed_work	init_work;
-- 
2.7.4




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux