nalika / rpms / grub2

Forked from rpms/grub2 2 years ago
Clone

Blame SOURCES/0215-Initialize-USB-ports-in-parallel-to-speed-up-boot.patch

f96e0b
From b528ebd33741511b054926e6076b23ab0637f6da Mon Sep 17 00:00:00 2001
f96e0b
From: Vladimir 'phcoder' Serbinenko <phcoder@gmail.com>
f96e0b
Date: Tue, 19 Mar 2013 23:06:44 +0100
f96e0b
Subject: [PATCH 215/482] 	Initialize USB ports in parallel to speed-up
f96e0b
 boot.
f96e0b
f96e0b
---
f96e0b
 ChangeLog                  |   4 +
f96e0b
 grub-core/bus/usb/usb.c    |  38 ------
f96e0b
 grub-core/bus/usb/usbhub.c | 320 +++++++++++++++++++++++++++++----------------
f96e0b
 include/grub/usb.h         |  16 +++
f96e0b
 4 files changed, 228 insertions(+), 150 deletions(-)
f96e0b
f96e0b
diff --git a/ChangeLog b/ChangeLog
f96e0b
index 725fbe2..dd9c97a 100644
f96e0b
--- a/ChangeLog
f96e0b
+++ b/ChangeLog
f96e0b
@@ -1,5 +1,9 @@
f96e0b
 2013-03-19  Vladimir Serbinenko  <phcoder@gmail.com>
f96e0b
 
f96e0b
+	Initialize USB ports in parallel to speed-up boot.
f96e0b
+
f96e0b
+2013-03-19  Vladimir Serbinenko  <phcoder@gmail.com>
f96e0b
+
f96e0b
 	Fix USB devices not being detected when requested
f96e0b
 	due to delayed attach.
f96e0b
 
f96e0b
diff --git a/grub-core/bus/usb/usb.c b/grub-core/bus/usb/usb.c
f96e0b
index 108c69b..024190e 100644
f96e0b
--- a/grub-core/bus/usb/usb.c
f96e0b
+++ b/grub-core/bus/usb/usb.c
f96e0b
@@ -26,46 +26,8 @@
f96e0b
 
f96e0b
 GRUB_MOD_LICENSE ("GPLv3+");
f96e0b
 
f96e0b
-static grub_usb_controller_dev_t grub_usb_list;
f96e0b
 static struct grub_usb_attach_desc *attach_hooks;
f96e0b
 
f96e0b
-/* Iterate over all controllers found by the driver.  */
f96e0b
-static int
f96e0b
-grub_usb_controller_dev_register_iter (grub_usb_controller_t dev, void *data)
f96e0b
-{
f96e0b
-  grub_usb_controller_dev_t usb = data;
f96e0b
-
f96e0b
-  dev->dev = usb;
f96e0b
-
f96e0b
-  /* Enable the ports of the USB Root Hub.  */
f96e0b
-  grub_usb_root_hub (dev);
f96e0b
-
f96e0b
-  return 0;
f96e0b
-}
f96e0b
-
f96e0b
-void
f96e0b
-grub_usb_controller_dev_register (grub_usb_controller_dev_t usb)
f96e0b
-{
f96e0b
-  usb->next = grub_usb_list;
f96e0b
-  grub_usb_list = usb;
f96e0b
-
f96e0b
-  if (usb->iterate)
f96e0b
-    usb->iterate (grub_usb_controller_dev_register_iter, usb);
f96e0b
-}
f96e0b
-
f96e0b
-void
f96e0b
-grub_usb_controller_dev_unregister (grub_usb_controller_dev_t usb)
f96e0b
-{
f96e0b
-  grub_usb_controller_dev_t *p, q;
f96e0b
-
f96e0b
-  for (p = &grub_usb_list, q = *p; q; p = &(q->next), q = q->next)
f96e0b
-    if (q == usb)
f96e0b
-      {
f96e0b
-	*p = q->next;
f96e0b
-	break;
f96e0b
-      }
f96e0b
-}
f96e0b
-
f96e0b
 #if 0
f96e0b
 /* Context for grub_usb_controller_iterate.  */
f96e0b
 struct grub_usb_controller_iterate_ctx
f96e0b
diff --git a/grub-core/bus/usb/usbhub.c b/grub-core/bus/usb/usbhub.c
f96e0b
index 253e49f..d0be80d 100644
f96e0b
--- a/grub-core/bus/usb/usbhub.c
f96e0b
+++ b/grub-core/bus/usb/usbhub.c
f96e0b
@@ -41,6 +41,7 @@ struct grub_usb_hub
f96e0b
 };
f96e0b
 
f96e0b
 static struct grub_usb_hub *hubs;
f96e0b
+static grub_usb_controller_dev_t grub_usb_list;
f96e0b
 
f96e0b
 /* Add a device that currently has device number 0 and resides on
f96e0b
    CONTROLLER, the Hub reported that the device speed is SPEED.  */
f96e0b
@@ -146,10 +147,15 @@ grub_usb_add_hub (grub_usb_device_t dev)
f96e0b
   grub_dprintf ("usb", "Hub set configuration\n");
f96e0b
   grub_usb_set_configuration (dev, 1);
f96e0b
 
f96e0b
-  dev->children = grub_zalloc (hubdesc.portcnt * sizeof (dev->children[0]));
f96e0b
-  if (!dev->children)
f96e0b
-    return GRUB_USB_ERR_INTERNAL;
f96e0b
   dev->nports = hubdesc.portcnt;
f96e0b
+  dev->children = grub_zalloc (hubdesc.portcnt * sizeof (dev->children[0]));
f96e0b
+  dev->ports = grub_zalloc (dev->nports * sizeof (dev->ports[0]));
f96e0b
+  if (!dev->children || !dev->ports)
f96e0b
+    {
f96e0b
+      grub_free (dev->children);
f96e0b
+      grub_free (dev->ports);
f96e0b
+      return GRUB_USB_ERR_INTERNAL;
f96e0b
+    }
f96e0b
 
f96e0b
   /* Power on all Hub ports.  */
f96e0b
   for (i = 1; i <= hubdesc.portcnt; i++)
f96e0b
@@ -197,46 +203,6 @@ attach_root_port (struct grub_usb_hub *hub, int portno,
f96e0b
 {
f96e0b
   grub_usb_device_t dev;
f96e0b
   grub_err_t err;
f96e0b
-  int total, i;
f96e0b
-  grub_usb_speed_t current_speed = GRUB_USB_SPEED_NONE;
f96e0b
-  int changed=0;
f96e0b
-
f96e0b
-  grub_boot_time ("detect_dev USB root portno=%d\n", portno);
f96e0b
-
f96e0b
-#if 0
f96e0b
-/* Specification does not say about disabling of port when device
f96e0b
- * connected. If disabling is really necessary for some devices,
f96e0b
- * delete this #if 0 and related #endif */
f96e0b
-  /* Disable the port. XXX: Why? */
f96e0b
-  err = hub->controller->dev->portstatus (hub->controller, portno, 0);
f96e0b
-  if (err)
f96e0b
-    return;
f96e0b
-#endif
f96e0b
-
f96e0b
-  grub_boot_time ("Before the stable power wait portno=%d", portno);
f96e0b
-
f96e0b
-  /* Wait for completion of insertion and stable power (USB spec.)
f96e0b
-   * Should be at least 100ms, some devices requires more...
f96e0b
-   * There is also another thing - some devices have worse contacts
f96e0b
-   * and connected signal is unstable for some time - we should handle
f96e0b
-   * it - but prevent deadlock in case when device is too faulty... */
f96e0b
-  for (total = i = 0; (i < 250) && (total < 2000); i++, total++)
f96e0b
-    {
f96e0b
-      grub_millisleep (1);
f96e0b
-      current_speed = hub->controller->dev->detect_dev
f96e0b
-                        (hub->controller, portno, &changed);
f96e0b
-      if (current_speed == GRUB_USB_SPEED_NONE)
f96e0b
-        i = 0;
f96e0b
-    }
f96e0b
-
f96e0b
-  grub_boot_time ("After the stable power wait portno=%d", portno);
f96e0b
-
f96e0b
-  grub_dprintf ("usb", "total=%d\n", total);
f96e0b
-  if (total >= 2000)
f96e0b
-    {
f96e0b
-      grub_boot_time ("Root port timeout");
f96e0b
-      return;
f96e0b
-    }
f96e0b
 
f96e0b
   grub_boot_time ("After detect_dev");
f96e0b
 
f96e0b
@@ -267,12 +233,14 @@ attach_root_port (struct grub_usb_hub *hub, int portno,
f96e0b
   grub_boot_time ("Attached root port");
f96e0b
 }
f96e0b
 
f96e0b
-grub_usb_err_t
f96e0b
-grub_usb_root_hub (grub_usb_controller_t controller)
f96e0b
+/* Iterate over all controllers found by the driver.  */
f96e0b
+static int
f96e0b
+grub_usb_controller_dev_register_iter (grub_usb_controller_t controller, void *data)
f96e0b
 {
f96e0b
-  int i;
f96e0b
+  grub_usb_controller_dev_t usb = data;
f96e0b
   struct grub_usb_hub *hub;
f96e0b
-  int changed=0;
f96e0b
+
f96e0b
+  controller->dev = usb;
f96e0b
 
f96e0b
   grub_boot_time ("Registering USB root hub");
f96e0b
 
f96e0b
@@ -295,29 +263,118 @@ grub_usb_root_hub (grub_usb_controller_t controller)
f96e0b
   /* Query the number of ports the root Hub has.  */
f96e0b
   hub->nports = controller->dev->hubports (controller);
f96e0b
   hub->devices = grub_zalloc (sizeof (hub->devices[0]) * hub->nports);
f96e0b
-  if (!hub->devices)
f96e0b
+  usb->ports = grub_zalloc (sizeof (usb->ports[0]) * hub->nports);
f96e0b
+  if (!hub->devices || !usb->ports)
f96e0b
     {
f96e0b
+      grub_free (hub->devices);
f96e0b
+      grub_free (usb->ports);
f96e0b
       grub_free (hub->controller);
f96e0b
       grub_free (hub);
f96e0b
-      return GRUB_USB_ERR_INTERNAL;
f96e0b
+      grub_print_error ();
f96e0b
+      return 0;
f96e0b
     }
f96e0b
 
f96e0b
-  for (i = 0; i < hub->nports; i++)
f96e0b
+  return 0;
f96e0b
+}
f96e0b
+
f96e0b
+void
f96e0b
+grub_usb_controller_dev_unregister (grub_usb_controller_dev_t usb)
f96e0b
+{
f96e0b
+  grub_usb_controller_dev_t *p, q;
f96e0b
+
f96e0b
+  for (p = &grub_usb_list, q = *p; q; p = &(q->next), q = q->next)
f96e0b
+    if (q == usb)
f96e0b
+      {
f96e0b
+	*p = q->next;
f96e0b
+	break;
f96e0b
+      }
f96e0b
+}
f96e0b
+
f96e0b
+void
f96e0b
+grub_usb_controller_dev_register (grub_usb_controller_dev_t usb)
f96e0b
+{
f96e0b
+  int portno;
f96e0b
+  int continue_waiting = 0;
f96e0b
+  struct grub_usb_hub *hub;
f96e0b
+
f96e0b
+  usb->next = grub_usb_list;
f96e0b
+  grub_usb_list = usb;
f96e0b
+
f96e0b
+  if (usb->iterate)
f96e0b
+    usb->iterate (grub_usb_controller_dev_register_iter, usb);
f96e0b
+
f96e0b
+  grub_boot_time ("waiting for stable power on USB root\n");
f96e0b
+
f96e0b
+  while (1)
f96e0b
     {
f96e0b
-      grub_usb_speed_t speed;
f96e0b
-      if (!controller->dev->pending_reset)
f96e0b
-        {
f96e0b
-          speed = controller->dev->detect_dev (hub->controller, i,
f96e0b
-					       &changed);
f96e0b
-
f96e0b
-          if (speed != GRUB_USB_SPEED_NONE)
f96e0b
-	    attach_root_port (hub, i, speed);
f96e0b
-        }
f96e0b
+      for (hub = hubs; hub; hub = hub->next)
f96e0b
+	if (hub->controller->dev == usb)
f96e0b
+	  {
f96e0b
+	    /* Wait for completion of insertion and stable power (USB spec.)
f96e0b
+	     * Should be at least 100ms, some devices requires more...
f96e0b
+	     * There is also another thing - some devices have worse contacts
f96e0b
+	     * and connected signal is unstable for some time - we should handle
f96e0b
+	     * it - but prevent deadlock in case when device is too faulty... */
f96e0b
+	    for (portno = 0; portno < hub->nports; portno++)
f96e0b
+	      {
f96e0b
+		grub_usb_speed_t speed;
f96e0b
+		int changed = 0;
f96e0b
+
f96e0b
+		speed = hub->controller->dev->detect_dev (hub->controller, portno,
f96e0b
+							  &changed);
f96e0b
+      
f96e0b
+		if (usb->ports[portno].state == PORT_STATE_NORMAL
f96e0b
+		    && speed != GRUB_USB_SPEED_NONE)
f96e0b
+		  {
f96e0b
+		    usb->ports[portno].soft_limit_time = grub_get_time_ms () + 250;
f96e0b
+		    usb->ports[portno].hard_limit_time = usb->ports[portno].soft_limit_time + 1750;
f96e0b
+		    usb->ports[portno].state = PORT_STATE_WAITING_FOR_STABLE_POWER;
f96e0b
+		    continue_waiting++;
f96e0b
+		    continue;
f96e0b
+		  }
f96e0b
+
f96e0b
+		if (usb->ports[portno].state == PORT_STATE_WAITING_FOR_STABLE_POWER
f96e0b
+		    && speed == GRUB_USB_SPEED_NONE)
f96e0b
+		  {
f96e0b
+		    usb->ports[portno].soft_limit_time = grub_get_time_ms () + 250;
f96e0b
+		    continue;
f96e0b
+		  }
f96e0b
+		if (usb->ports[portno].state == PORT_STATE_WAITING_FOR_STABLE_POWER
f96e0b
+		    && grub_get_time_ms () > usb->ports[portno].soft_limit_time)
f96e0b
+		  {
f96e0b
+		    usb->ports[portno].state = PORT_STATE_STABLE_POWER;
f96e0b
+		    continue_waiting--;
f96e0b
+		    continue;
f96e0b
+		  }
f96e0b
+		if (usb->ports[portno].state == PORT_STATE_WAITING_FOR_STABLE_POWER
f96e0b
+		    && grub_get_time_ms () > usb->ports[portno].hard_limit_time)
f96e0b
+		  {
f96e0b
+		    usb->ports[portno].state = PORT_STATE_FAILED_DEVICE;
f96e0b
+		    continue_waiting--;
f96e0b
+		    continue;
f96e0b
+		  }
f96e0b
+	      }
f96e0b
+	  }
f96e0b
+      if (!continue_waiting)
f96e0b
+	break;
f96e0b
+      grub_millisleep (1);
f96e0b
     }
f96e0b
 
f96e0b
-  grub_boot_time ("USB root hub registered");
f96e0b
+  grub_boot_time ("After the stable power wait on USB root");
f96e0b
 
f96e0b
-  return GRUB_USB_ERR_NONE;
f96e0b
+  for (hub = hubs; hub; hub = hub->next)
f96e0b
+    if (hub->controller->dev == usb)
f96e0b
+      for (portno = 0; portno < hub->nports; portno++)
f96e0b
+	if (usb->ports[portno].state == PORT_STATE_STABLE_POWER)
f96e0b
+	  {
f96e0b
+	    grub_usb_speed_t speed;
f96e0b
+	    int changed = 0;
f96e0b
+	    usb->ports[portno].state = PORT_STATE_NORMAL;
f96e0b
+	    speed = hub->controller->dev->detect_dev (hub->controller, portno, &changed);
f96e0b
+	    attach_root_port (hub, portno, speed);
f96e0b
+	  }
f96e0b
+
f96e0b
+  grub_boot_time ("USB root hub registered");
f96e0b
 }
f96e0b
 
f96e0b
 static void detach_device (grub_usb_device_t dev);
f96e0b
@@ -349,6 +406,71 @@ detach_device (grub_usb_device_t dev)
f96e0b
   grub_usb_devs[dev->addr] = 0;
f96e0b
 }
f96e0b
 
f96e0b
+static int
f96e0b
+wait_power_nonroot_hub (grub_usb_device_t dev)
f96e0b
+{
f96e0b
+  grub_usb_err_t err;
f96e0b
+  int continue_waiting = 0;
f96e0b
+  unsigned i;
f96e0b
+  
f96e0b
+  for (i = 1; i <= dev->nports; i++)
f96e0b
+    if (dev->ports[i - 1].state == PORT_STATE_WAITING_FOR_STABLE_POWER)
f96e0b
+      {
f96e0b
+	grub_uint64_t tm;
f96e0b
+	grub_uint32_t current_status = 0;
f96e0b
+
f96e0b
+	/* Get the port status.  */
f96e0b
+	err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
f96e0b
+					  | GRUB_USB_REQTYPE_CLASS
f96e0b
+					  | GRUB_USB_REQTYPE_TARGET_OTHER),
f96e0b
+				    GRUB_USB_REQ_GET_STATUS,
f96e0b
+				    0, i,
f96e0b
+				    sizeof (current_status),
f96e0b
+				    (char *) &current_status);
f96e0b
+	if (err)
f96e0b
+	  {
f96e0b
+	    dev->ports[i - 1].state = PORT_STATE_FAILED_DEVICE;
f96e0b
+	    continue;
f96e0b
+	  }
f96e0b
+	tm = grub_get_time_ms ();
f96e0b
+	if (!(current_status & GRUB_USB_HUB_STATUS_PORT_CONNECTED))
f96e0b
+	  dev->ports[i - 1].soft_limit_time = tm + 250;
f96e0b
+	if (tm >= dev->ports[i - 1].soft_limit_time)
f96e0b
+	  {
f96e0b
+	    if (dev->controller.dev->pending_reset)
f96e0b
+	      continue;
f96e0b
+	    /* Now do reset of port. */
f96e0b
+	    grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
f96e0b
+					| GRUB_USB_REQTYPE_CLASS
f96e0b
+					| GRUB_USB_REQTYPE_TARGET_OTHER),
f96e0b
+				  GRUB_USB_REQ_SET_FEATURE,
f96e0b
+				  GRUB_USB_HUB_FEATURE_PORT_RESET,
f96e0b
+				  i, 0, 0);
f96e0b
+	    dev->ports[i - 1].state = PORT_STATE_NORMAL;
f96e0b
+	    grub_boot_time ("Resetting port %d", i);
f96e0b
+
f96e0b
+	    rescan = 1;
f96e0b
+	    /* We cannot reset more than one device at the same time !
f96e0b
+	     * Resetting more devices together results in very bad
f96e0b
+	     * situation: more than one device has default address 0
f96e0b
+	     * at the same time !!!
f96e0b
+	     * Additionaly, we cannot perform another reset
f96e0b
+	     * anywhere on the same OHCI controller until
f96e0b
+	     * we will finish addressing of reseted device ! */
f96e0b
+	    dev->controller.dev->pending_reset = grub_get_time_ms () + 5000;
f96e0b
+	    npending++;
f96e0b
+	    continue;
f96e0b
+	  }
f96e0b
+	if (tm >= dev->ports[i - 1].hard_limit_time)
f96e0b
+	  {
f96e0b
+	    dev->ports[i - 1].state = PORT_STATE_FAILED_DEVICE;
f96e0b
+	    continue;
f96e0b
+	  }
f96e0b
+	continue_waiting = 1;
f96e0b
+      }
f96e0b
+  return continue_waiting && dev->controller.dev->pending_reset == 0;
f96e0b
+}
f96e0b
+
f96e0b
 static void
f96e0b
 poll_nonroot_hub (grub_usb_device_t dev)
f96e0b
 {
f96e0b
@@ -356,7 +478,6 @@ poll_nonroot_hub (grub_usb_device_t dev)
f96e0b
   unsigned i;
f96e0b
   grub_uint8_t changed;
f96e0b
   grub_size_t actual, len;
f96e0b
-  int j, total;
f96e0b
 
f96e0b
   if (!dev->hub_transfer)
f96e0b
     return;
f96e0b
@@ -382,9 +503,9 @@ poll_nonroot_hub (grub_usb_device_t dev)
f96e0b
   for (i = 1; i <= dev->nports; i++)
f96e0b
     {
f96e0b
       grub_uint32_t status;
f96e0b
-      grub_uint32_t current_status = 0;
f96e0b
 
f96e0b
-      if (!(changed & (1 << i)))
f96e0b
+      if (!(changed & (1 << i))
f96e0b
+	  || dev->ports[i - 1].state == PORT_STATE_WAITING_FOR_STABLE_POWER)
f96e0b
 	continue;
f96e0b
 
f96e0b
       /* Get the port status.  */
f96e0b
@@ -444,52 +565,10 @@ poll_nonroot_hub (grub_usb_device_t dev)
f96e0b
 	       * There is also another thing - some devices have worse contacts
f96e0b
 	       * and connected signal is unstable for some time - we should handle
f96e0b
 	       * it - but prevent deadlock in case when device is too faulty... */
f96e0b
-              for (total = j = 0; (j < 250) && (total < 2000); j++, total++)
f96e0b
-                {
f96e0b
-                  grub_millisleep (1);
f96e0b
-                  /* Get the port status.  */
f96e0b
-                  err = grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
f96e0b
-					       | GRUB_USB_REQTYPE_CLASS
f96e0b
-					       | GRUB_USB_REQTYPE_TARGET_OTHER),
f96e0b
-				              GRUB_USB_REQ_GET_STATUS,
f96e0b
-				              0, i,
f96e0b
-				              sizeof (current_status),
f96e0b
-				              (char *) &current_status);
f96e0b
-                  if (err)
f96e0b
-                    {
f96e0b
-                      total = 2000;
f96e0b
-	              break;
f96e0b
-                    }
f96e0b
-                  if (!(current_status & GRUB_USB_HUB_STATUS_PORT_CONNECTED))
f96e0b
-                    j = 0;
f96e0b
-                }
f96e0b
-
f96e0b
-	      grub_boot_time ("After the stable power wait portno=%d", i);
f96e0b
-
f96e0b
-              grub_dprintf ("usb", "(non-root) total=%d\n", total);
f96e0b
-              if (total >= 2000)
f96e0b
-                continue;
f96e0b
-
f96e0b
-              /* Now do reset of port. */
f96e0b
-	      grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
f96e0b
-					  | GRUB_USB_REQTYPE_CLASS
f96e0b
-					  | GRUB_USB_REQTYPE_TARGET_OTHER),
f96e0b
-				    GRUB_USB_REQ_SET_FEATURE,
f96e0b
-				    GRUB_USB_HUB_FEATURE_PORT_RESET,
f96e0b
-				    i, 0, 0);
f96e0b
-	      grub_boot_time ("Resetting port %d", i);
f96e0b
-
f96e0b
-	      rescan = 1;
f96e0b
-	      /* We cannot reset more than one device at the same time !
f96e0b
-	       * Resetting more devices together results in very bad
f96e0b
-	       * situation: more than one device has default address 0
f96e0b
-	       * at the same time !!!
f96e0b
-	       * Additionaly, we cannot perform another reset
f96e0b
-	       * anywhere on the same OHCI controller until
f96e0b
-	       * we will finish addressing of reseted device ! */
f96e0b
-              dev->controller.dev->pending_reset = grub_get_time_ms () + 5000;
f96e0b
-	      npending++;
f96e0b
-              return;
f96e0b
+	      dev->ports[i - 1].soft_limit_time = grub_get_time_ms () + 250;
f96e0b
+	      dev->ports[i - 1].hard_limit_time = dev->ports[i - 1].soft_limit_time + 1750;
f96e0b
+	      dev->ports[i - 1].state = PORT_STATE_WAITING_FOR_STABLE_POWER;
f96e0b
+	      continue;
f96e0b
 	    }
f96e0b
 	}
f96e0b
 
f96e0b
@@ -580,6 +659,8 @@ grub_usb_poll_devices (int wait_for_completion)
f96e0b
 	}
f96e0b
     }
f96e0b
 
f96e0b
+  grub_boot_time ("Probing USB device driver");
f96e0b
+
f96e0b
   while (1)
f96e0b
     {
f96e0b
       rescan = 0;
f96e0b
@@ -592,11 +673,26 @@ grub_usb_poll_devices (int wait_for_completion)
f96e0b
 	  if (dev && dev->descdev.class == 0x09)
f96e0b
 	    poll_nonroot_hub (dev);
f96e0b
 	}
f96e0b
+
f96e0b
+      while (1)
f96e0b
+	{
f96e0b
+	  int continue_waiting = 0;
f96e0b
+	  for (i = 0; i < GRUB_USBHUB_MAX_DEVICES; i++)
f96e0b
+	    {
f96e0b
+	      grub_usb_device_t dev = grub_usb_devs[i];
f96e0b
+	    
f96e0b
+	      if (dev && dev->descdev.class == 0x09)
f96e0b
+		continue_waiting = continue_waiting || wait_power_nonroot_hub (dev);
f96e0b
+	    }
f96e0b
+	  if (!continue_waiting)
f96e0b
+	    break;
f96e0b
+	  grub_millisleep (1);
f96e0b
+	}
f96e0b
+
f96e0b
       if (!(rescan || (npending && wait_for_completion)))
f96e0b
 	break;
f96e0b
-      grub_millisleep (50);
f96e0b
+      grub_millisleep (25);
f96e0b
     }
f96e0b
-
f96e0b
 }
f96e0b
 
f96e0b
 int
f96e0b
diff --git a/include/grub/usb.h b/include/grub/usb.h
f96e0b
index 7164dd5..12a456b 100644
f96e0b
--- a/include/grub/usb.h
f96e0b
+++ b/include/grub/usb.h
f96e0b
@@ -121,6 +121,8 @@ struct grub_usb_controller_dev
f96e0b
 
f96e0b
   grub_usb_speed_t (*detect_dev) (grub_usb_controller_t dev, int port, int *changed);
f96e0b
 
f96e0b
+  struct grub_usb_hub_port *ports;
f96e0b
+
f96e0b
   /* Per controller flag - port reset pending, don't do another reset */
f96e0b
   grub_uint64_t pending_reset;
f96e0b
 
f96e0b
@@ -170,6 +172,18 @@ struct grub_usb_configuration
f96e0b
   struct grub_usb_interface interf[32];
f96e0b
 };
f96e0b
 
f96e0b
+struct grub_usb_hub_port
f96e0b
+{
f96e0b
+  grub_uint64_t soft_limit_time;
f96e0b
+  grub_uint64_t hard_limit_time;
f96e0b
+  enum { 
f96e0b
+    PORT_STATE_NORMAL = 0,
f96e0b
+    PORT_STATE_WAITING_FOR_STABLE_POWER = 1,
f96e0b
+    PORT_STATE_FAILED_DEVICE = 2,
f96e0b
+    PORT_STATE_STABLE_POWER = 3,
f96e0b
+  } state;
f96e0b
+};
f96e0b
+
f96e0b
 struct grub_usb_device
f96e0b
 {
f96e0b
   /* The device descriptor of this device.  */
f96e0b
@@ -204,6 +218,8 @@ struct grub_usb_device
f96e0b
   /* Number of hub ports.  */
f96e0b
   unsigned nports;
f96e0b
 
f96e0b
+  struct grub_usb_hub_port *ports;
f96e0b
+
f96e0b
   grub_usb_transfer_t hub_transfer;
f96e0b
 
f96e0b
   grub_uint32_t statuschange;
f96e0b
-- 
f96e0b
1.8.2.1
f96e0b