* [PATCH v3] usb: ehci: Only sleep for post-resume handover if devices use persist
@ 2013-04-25 16:08 Julius Werner
2013-05-17 0:42 ` Greg Kroah-Hartman
0 siblings, 1 reply; 3+ messages in thread
From: Julius Werner @ 2013-04-25 16:08 UTC (permalink / raw)
To: linux-kernel
Cc: Alan Stern, Greg Kroah-Hartman, linux-usb, Vincent Palatin,
Sameer Nanda, Julius Werner
The current EHCI code sleeps a flat 110ms in the resume path if there
was a USB 1.1 device connected to its companion controller during
suspend, waiting for the device to reappear and reset so that it can be
handed back to the companion. This is necessary if the device uses
persist, so that the companion controller can actually see it during its
own resume path.
However, if the device doesn't use persist, this is entirely
unnecessary. We might just as well ignore it and have the normal device
detection/reset/handoff code handle it asynchronously when it eventually
shows up. As USB 1.1 devices are almost exclusively HIDs these days (for
which persist has no value), this can allow distros to shave another
tenth of a second off their resume time.
In order to enable this optimization, the patch also adds a new
usb_for_each_dev() iterator that is exported by the USB core and wraps
bus_for_each_dev() with the logic to differentiate between struct
usb_device and struct usb_interface on the usb_bus_type bus.
Signed-off-by: Julius Werner <jwerner@chromium.org>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
---
drivers/usb/core/usb.c | 33 +++++++++++++++++++++++++++++++++
drivers/usb/host/ehci-hub.c | 17 +++++++++++++++++
include/linux/usb.h | 1 +
3 files changed, 51 insertions(+)
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index f81b925..eaf09e6 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -209,6 +209,39 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
}
EXPORT_SYMBOL_GPL(usb_find_interface);
+struct each_dev_arg {
+ void *data;
+ int (*fn)(struct usb_device *, void *);
+};
+
+static int __each_dev(struct device *dev, void *data)
+{
+ struct each_dev_arg *arg = (struct each_dev_arg *)data;
+
+ /* There are struct usb_interface on the same bus, filter them out */
+ if (!is_usb_device(dev))
+ return 0;
+
+ return arg->fn(container_of(dev, struct usb_device, dev), arg->data);
+}
+
+/**
+ * usb_for_each_dev - iterate over all USB devices in the system
+ * @data: data pointer that will be handed to the callback function
+ * @fn: callback function to be called for each USB device
+ *
+ * Iterate over all USB devices and call @fn for each, passing it @data. If it
+ * returns anything other than 0, we break the iteration prematurely and return
+ * that value.
+ */
+int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void *))
+{
+ struct each_dev_arg arg = {data, fn};
+
+ return bus_for_each_dev(&usb_bus_type, NULL, &arg, __each_dev);
+}
+EXPORT_SYMBOL_GPL(usb_for_each_dev);
+
/**
* usb_release_dev - free a usb device structure when all users of it are finished.
* @dev: device that's been disconnected
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 7d06e77..a46452d 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -42,6 +42,13 @@ static int ehci_hub_control(
u16 wLength
);
+static int persist_enabled_on_companion(struct usb_device *udev, void *unused)
+{
+ return !udev->maxchild && udev->persist_enabled &&
+ udev->bus->root_hub->speed < USB_SPEED_HIGH;
+}
+
/* After a power loss, ports that were owned by the companion must be
* reset so that the companion can still own them.
*/
@@ -56,6 +63,16 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
if (!ehci->owned_ports)
return;
+ /*
+ * USB 1.1 devices are mostly HIDs, which don't need to persist across
+ * suspends. If we ensure that none of our companion's devices have
+ * persist_enabled (by looking through all USB 1.1 buses in the system),
+ * we can skip this and avoid slowing resume down. Devices without
+ * persist will just get reenumerated shortly after resume anyway.
+ */
+ if (!usb_for_each_dev(NULL, persist_enabled_on_companion))
+ return;
+
/* Make sure the ports are powered */
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 4d22d0f..559cb39 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -719,6 +719,7 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
extern int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id);
+extern int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void *));
extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
int minor);
extern struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
--
1.7.12.4
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH v3] usb: ehci: Only sleep for post-resume handover if devices use persist
2013-04-25 16:08 [PATCH v3] usb: ehci: Only sleep for post-resume handover if devices use persist Julius Werner
@ 2013-05-17 0:42 ` Greg Kroah-Hartman
2013-05-17 19:08 ` [PATCH v4] " Julius Werner
0 siblings, 1 reply; 3+ messages in thread
From: Greg Kroah-Hartman @ 2013-05-17 0:42 UTC (permalink / raw)
To: Julius Werner
Cc: linux-kernel, Alan Stern, linux-usb, Vincent Palatin,
Sameer Nanda
On Thu, Apr 25, 2013 at 09:08:27AM -0700, Julius Werner wrote:
> The current EHCI code sleeps a flat 110ms in the resume path if there
> was a USB 1.1 device connected to its companion controller during
> suspend, waiting for the device to reappear and reset so that it can be
> handed back to the companion. This is necessary if the device uses
> persist, so that the companion controller can actually see it during its
> own resume path.
>
> However, if the device doesn't use persist, this is entirely
> unnecessary. We might just as well ignore it and have the normal device
> detection/reset/handoff code handle it asynchronously when it eventually
> shows up. As USB 1.1 devices are almost exclusively HIDs these days (for
> which persist has no value), this can allow distros to shave another
> tenth of a second off their resume time.
>
> In order to enable this optimization, the patch also adds a new
> usb_for_each_dev() iterator that is exported by the USB core and wraps
> bus_for_each_dev() with the logic to differentiate between struct
> usb_device and struct usb_interface on the usb_bus_type bus.
>
> Signed-off-by: Julius Werner <jwerner@chromium.org>
> Acked-by: Alan Stern <stern@rowland.harvard.edu>
> ---
> drivers/usb/core/usb.c | 33 +++++++++++++++++++++++++++++++++
> drivers/usb/host/ehci-hub.c | 17 +++++++++++++++++
> include/linux/usb.h | 1 +
> 3 files changed, 51 insertions(+)
This patch is corrupted somehow, but I can't figure out how.
I'm getting the error:
checking file drivers/usb/core/usb.c
checking file drivers/usb/host/ehci-hub.c
patch: **** malformed patch at line 164: @@ -56,6 +63,16 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
when trying to apply it. git also doesn't like it.
Care to fix this up and resend it so I can apply it?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v4] usb: ehci: Only sleep for post-resume handover if devices use persist
2013-05-17 0:42 ` Greg Kroah-Hartman
@ 2013-05-17 19:08 ` Julius Werner
0 siblings, 0 replies; 3+ messages in thread
From: Julius Werner @ 2013-05-17 19:08 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: linux-kernel, linux-usb, Alan Stern, Vincent Palatin,
Sameer Nanda, Julius Werner
The current EHCI code sleeps a flat 110ms in the resume path if there
was a USB 1.1 device connected to its companion controller during
suspend, waiting for the device to reappear and reset so that it can be
handed back to the companion. This is necessary if the device uses
persist, so that the companion controller can actually see it during its
own resume path.
However, if the device doesn't use persist, this is entirely
unnecessary. We might just as well ignore it and have the normal device
detection/reset/handoff code handle it asynchronously when it eventually
shows up. As USB 1.1 devices are almost exclusively HIDs these days (for
which persist has no value), this can allow distros to shave another
tenth of a second off their resume time.
In order to enable this optimization, the patch also adds a new
usb_for_each_dev() iterator that is exported by the USB core and wraps
bus_for_each_dev() with the logic to differentiate between struct
usb_device and struct usb_interface on the usb_bus_type bus.
Signed-off-by: Julius Werner <jwerner@chromium.org>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
---
drivers/usb/core/usb.c | 33 +++++++++++++++++++++++++++++++++
drivers/usb/host/ehci-hub.c | 16 ++++++++++++++++
include/linux/usb.h | 1 +
3 files changed, 50 insertions(+)
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index b10da72..7dad603 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -209,6 +209,39 @@ struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
}
EXPORT_SYMBOL_GPL(usb_find_interface);
+struct each_dev_arg {
+ void *data;
+ int (*fn)(struct usb_device *, void *);
+};
+
+static int __each_dev(struct device *dev, void *data)
+{
+ struct each_dev_arg *arg = (struct each_dev_arg *)data;
+
+ /* There are struct usb_interface on the same bus, filter them out */
+ if (!is_usb_device(dev))
+ return 0;
+
+ return arg->fn(container_of(dev, struct usb_device, dev), arg->data);
+}
+
+/**
+ * usb_for_each_dev - iterate over all USB devices in the system
+ * @data: data pointer that will be handed to the callback function
+ * @fn: callback function to be called for each USB device
+ *
+ * Iterate over all USB devices and call @fn for each, passing it @data. If it
+ * returns anything other than 0, we break the iteration prematurely and return
+ * that value.
+ */
+int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void *))
+{
+ struct each_dev_arg arg = {data, fn};
+
+ return bus_for_each_dev(&usb_bus_type, NULL, &arg, __each_dev);
+}
+EXPORT_SYMBOL_GPL(usb_for_each_dev);
+
/**
* usb_release_dev - free a usb device structure when all users of it are finished.
* @dev: device that's been disconnected
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 9ab4a4d..b2f6450 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -42,6 +42,12 @@ static int ehci_hub_control(
u16 wLength
);
+static int persist_enabled_on_companion(struct usb_device *udev, void *unused)
+{
+ return !udev->maxchild && udev->persist_enabled &&
+ udev->bus->root_hub->speed < USB_SPEED_HIGH;
+}
+
/* After a power loss, ports that were owned by the companion must be
* reset so that the companion can still own them.
*/
@@ -56,6 +62,16 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
if (!ehci->owned_ports)
return;
+ /*
+ * USB 1.1 devices are mostly HIDs, which don't need to persist across
+ * suspends. If we ensure that none of our companion's devices have
+ * persist_enabled (by looking through all USB 1.1 buses in the system),
+ * we can skip this and avoid slowing resume down. Devices without
+ * persist will just get reenumerated shortly after resume anyway.
+ */
+ if (!usb_for_each_dev(NULL, persist_enabled_on_companion))
+ return;
+
/* Make sure the ports are powered */
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
diff --git a/include/linux/usb.h b/include/linux/usb.h
index a0bee5a..b424e53 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -717,6 +717,7 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
extern int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id);
+extern int usb_for_each_dev(void *data, int (*fn)(struct usb_device *, void *));
extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
int minor);
extern struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
--
1.7.12.4
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2013-05-17 19:09 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-25 16:08 [PATCH v3] usb: ehci: Only sleep for post-resume handover if devices use persist Julius Werner
2013-05-17 0:42 ` Greg Kroah-Hartman
2013-05-17 19:08 ` [PATCH v4] " Julius Werner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox