CHROMIUM: usb: ehci: Only sleep for post-resume handover if devices use persist
[cascardo/linux.git] / drivers / usb / host / ehci-hub.c
index 38fe076..4adfe77 100644 (file)
@@ -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;
+
        /* Give the connections some time to appear */
        msleep(20);
 
@@ -612,7 +629,11 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
                        status = STS_PCD;
                }
        }
-       /* FIXME autosuspend idle root hubs */
+
+       /* If a resume is in progress, make sure it can finish */
+       if (ehci->resuming_ports)
+               mod_timer(&hcd->rh_timer, jiffies + msecs_to_jiffies(25));
+
        spin_unlock_irqrestore (&ehci->lock, flags);
        return status ? retval : 0;
 }
@@ -966,6 +987,12 @@ static int ehci_hub_control (
                if (!wIndex || wIndex > ports)
                        goto error;
                wIndex--;
+
+               /* test if the port is configured to be ignored */
+               if (ehci->port_used_bitmap &&
+                               !(ehci->port_used_bitmap & (1 << wIndex)))
+                       goto error_exit;
+
                temp = ehci_readl(ehci, status_reg);
                if (temp & PORT_OWNER)
                        break;