[PATCH] separate usb_address0 mutexes for each host

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

 



This patch creates a separate instance of the usb_address0 mutex for each host
controller, and attaches it to the host controller device struct. This allows
devices on separate hosts to be enumerated in parallel; saving time.

In the current code, there is a single, global instance of the usb_address0
mutex which is used for all devices on any host. This isn't completely
necessary, as this mutex is only needed to prevent address0 collisions for 
devices on the *same* host (usb 2.0 spec, sec 4.6.1). This superfluous coverage
can cause additional delay in system resume on systems with multiple hosts
(up to several seconds depending on what devices are attached).

For instance, if I have a USB WLAN and a KVM switch attached to two ports,
there's a chance that they could be initialized at the same time (e.g. on
system resume). They would both be in the Default state and would be
responding to requests from the default address (address 00H). If they were
on the same host, there'd be no way of differentiating the two devices and thus
the mutex is needed. But on separate hosts there's no chance of collision.

Signed-off-by: Todd Brandt <todd.e.brandt@xxxxxxxxxxxxxxx>
---
 drivers/usb/core/hcd.c  | 15 +++++++++++++--
 drivers/usb/core/hub.c  |  6 ++----
 include/linux/usb/hcd.h |  1 +
 3 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 9c4e292..b5d89eb 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2452,9 +2452,18 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
 			return NULL;
 		}
 		mutex_init(hcd->bandwidth_mutex);
+		hcd->usb_address0_mutex =
+			kmalloc(sizeof(*hcd->usb_address0_mutex), GFP_KERNEL);
+		if (!hcd->usb_address0_mutex) {
+			kfree(hcd);
+			dev_dbg(dev, "hcd usb_address0 mutex alloc failed\n");
+			return NULL;
+		}
+		mutex_init(hcd->usb_address0_mutex);
 		dev_set_drvdata(dev, hcd);
 	} else {
 		hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
+		hcd->usb_address0_mutex = primary_hcd->usb_address0_mutex;
 		hcd->primary_hcd = primary_hcd;
 		primary_hcd->primary_hcd = primary_hcd;
 		hcd->shared_hcd = primary_hcd;
@@ -2518,10 +2527,12 @@ static void hcd_release (struct kref *kref)
 {
 	struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
 
-	if (usb_hcd_is_primary_hcd(hcd))
+	if (usb_hcd_is_primary_hcd(hcd)) {
 		kfree(hcd->bandwidth_mutex);
-	else
+		kfree(hcd->usb_address0_mutex);
+	} else {
 		hcd->shared_hcd->shared_hcd = NULL;
+	}
 	kfree(hcd);
 }
 
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 090469e..804370e 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4016,8 +4016,6 @@ static int
 hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 		int retry_counter)
 {
-	static DEFINE_MUTEX(usb_address0_mutex);
-
 	struct usb_device	*hdev = hub->hdev;
 	struct usb_hcd		*hcd = bus_to_hcd(hdev->bus);
 	int			i, j, retval;
@@ -4040,7 +4038,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 	if (oldspeed == USB_SPEED_LOW)
 		delay = HUB_LONG_RESET_TIME;
 
-	mutex_lock(&usb_address0_mutex);
+	mutex_lock(hcd->usb_address0_mutex);
 
 	/* Reset the device; full speed may morph to high speed */
 	/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
@@ -4317,7 +4315,7 @@ fail:
 		hub_port_disable(hub, port1, 0);
 		update_devnum(udev, devnum);	/* for disconnect processing */
 	}
-	mutex_unlock(&usb_address0_mutex);
+	mutex_unlock(hcd->usb_address0_mutex);
 	return retval;
 }
 
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 485cd5e..a1f89b4 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -166,6 +166,7 @@ struct usb_hcd {
 	 * to the device, or resetting the bandwidth after a failed attempt.
 	 */
 	struct mutex		*bandwidth_mutex;
+	struct mutex		*usb_address0_mutex;
 	struct usb_hcd		*shared_hcd;
 	struct usb_hcd		*primary_hcd;
 
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




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

  Powered by Linux