aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-09-22 14:44:26 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-10-17 17:40:57 -0400
commit8520f38099ccfdac2147a0852f84ee7a8ee5e197 (patch)
treecefc0256d9af7088992b7ed02bdae8ba95bf68fa
parent3c4bb71f96c69ef3c81fda108c96b633a2000de2 (diff)
USB: change hub initialization sleeps to delayed_work
This patch (as1137) changes the hub_activate() routine, replacing the power-power-up and debounce delays with delayed_work calls. The idea is that on systems where the USB stack is compiled into the kernel rather than built as modules, these delays will no longer block the boot thread. At least 100 ms is saved for each root hub, which can add up to a significant savings in total boot time. Arjan van de Ven was very pleased to see that this shaved 700 ms off his computer's boot time. Since his total boot time is on the order of two seconds, the improvement is considerable. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: Arjan van de Ven <arjan@infradead.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/hub.c91
1 files changed, 81 insertions, 10 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index d99963873e37..b97110ca352d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -77,6 +77,7 @@ struct usb_hub {
77 unsigned has_indicators:1; 77 unsigned has_indicators:1;
78 u8 indicator[USB_MAXCHILDREN]; 78 u8 indicator[USB_MAXCHILDREN];
79 struct delayed_work leds; 79 struct delayed_work leds;
80 struct delayed_work init_work;
80}; 81};
81 82
82 83
@@ -515,10 +516,14 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
515} 516}
516EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer); 517EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer);
517 518
518static void hub_power_on(struct usb_hub *hub) 519/* If do_delay is false, return the number of milliseconds the caller
520 * needs to delay.
521 */
522static unsigned hub_power_on(struct usb_hub *hub, bool do_delay)
519{ 523{
520 int port1; 524 int port1;
521 unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; 525 unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;
526 unsigned delay;
522 u16 wHubCharacteristics = 527 u16 wHubCharacteristics =
523 le16_to_cpu(hub->descriptor->wHubCharacteristics); 528 le16_to_cpu(hub->descriptor->wHubCharacteristics);
524 529
@@ -537,7 +542,10 @@ static void hub_power_on(struct usb_hub *hub)
537 set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER); 542 set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);
538 543
539 /* Wait at least 100 msec for power to become stable */ 544 /* Wait at least 100 msec for power to become stable */
540 msleep(max(pgood_delay, (unsigned) 100)); 545 delay = max(pgood_delay, (unsigned) 100);
546 if (do_delay)
547 msleep(delay);
548 return delay;
541} 549}
542 550
543static int hub_hub_status(struct usb_hub *hub, 551static int hub_hub_status(struct usb_hub *hub,
@@ -599,21 +607,55 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
599} 607}
600 608
601enum hub_activation_type { 609enum hub_activation_type {
602 HUB_INIT, HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME 610 HUB_INIT, HUB_INIT2, HUB_INIT3,
611 HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME,
603}; 612};
604 613
614static void hub_init_func2(struct work_struct *ws);
615static void hub_init_func3(struct work_struct *ws);
616
605static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) 617static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
606{ 618{
607 struct usb_device *hdev = hub->hdev; 619 struct usb_device *hdev = hub->hdev;
608 int port1; 620 int port1;
609 int status; 621 int status;
610 bool need_debounce_delay = false; 622 bool need_debounce_delay = false;
623 unsigned delay;
624
625 /* Continue a partial initialization */
626 if (type == HUB_INIT2)
627 goto init2;
628 if (type == HUB_INIT3)
629 goto init3;
611 630
612 /* After a resume, port power should still be on. 631 /* After a resume, port power should still be on.
613 * For any other type of activation, turn it on. 632 * For any other type of activation, turn it on.
614 */ 633 */
615 if (type != HUB_RESUME) 634 if (type != HUB_RESUME) {
616 hub_power_on(hub); 635
636 /* Speed up system boot by using a delayed_work for the
637 * hub's initial power-up delays. This is pretty awkward
638 * and the implementation looks like a home-brewed sort of
639 * setjmp/longjmp, but it saves at least 100 ms for each
640 * root hub (assuming usbcore is compiled into the kernel
641 * rather than as a module). It adds up.
642 *
643 * This can't be done for HUB_RESUME or HUB_RESET_RESUME
644 * because for those activation types the ports have to be
645 * operational when we return. In theory this could be done
646 * for HUB_POST_RESET, but it's easier not to.
647 */
648 if (type == HUB_INIT) {
649 delay = hub_power_on(hub, false);
650 PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func2);
651 schedule_delayed_work(&hub->init_work,
652 msecs_to_jiffies(delay));
653 return; /* Continues at init2: below */
654 } else {
655 hub_power_on(hub, true);
656 }
657 }
658 init2:
617 659
618 /* Check each port and set hub->change_bits to let khubd know 660 /* Check each port and set hub->change_bits to let khubd know
619 * which ports need attention. 661 * which ports need attention.
@@ -692,9 +734,20 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
692 * If any port-status changes do occur during this delay, khubd 734 * If any port-status changes do occur during this delay, khubd
693 * will see them later and handle them normally. 735 * will see them later and handle them normally.
694 */ 736 */
695 if (need_debounce_delay) 737 if (need_debounce_delay) {
696 msleep(HUB_DEBOUNCE_STABLE); 738 delay = HUB_DEBOUNCE_STABLE;
697 739
740 /* Don't do a long sleep inside a workqueue routine */
741 if (type == HUB_INIT2) {
742 PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func3);
743 schedule_delayed_work(&hub->init_work,
744 msecs_to_jiffies(delay));
745 return; /* Continues at init3: below */
746 } else {
747 msleep(delay);
748 }
749 }
750 init3:
698 hub->quiescing = 0; 751 hub->quiescing = 0;
699 752
700 status = usb_submit_urb(hub->urb, GFP_NOIO); 753 status = usb_submit_urb(hub->urb, GFP_NOIO);
@@ -707,6 +760,21 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
707 kick_khubd(hub); 760 kick_khubd(hub);
708} 761}
709 762
763/* Implement the continuations for the delays above */
764static void hub_init_func2(struct work_struct *ws)
765{
766 struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work);
767
768 hub_activate(hub, HUB_INIT2);
769}
770
771static void hub_init_func3(struct work_struct *ws)
772{
773 struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work);
774
775 hub_activate(hub, HUB_INIT3);
776}
777
710enum hub_quiescing_type { 778enum hub_quiescing_type {
711 HUB_DISCONNECT, HUB_PRE_RESET, HUB_SUSPEND 779 HUB_DISCONNECT, HUB_PRE_RESET, HUB_SUSPEND
712}; 780};
@@ -716,6 +784,8 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
716 struct usb_device *hdev = hub->hdev; 784 struct usb_device *hdev = hub->hdev;
717 int i; 785 int i;
718 786
787 cancel_delayed_work_sync(&hub->init_work);
788
719 /* khubd and related activity won't re-trigger */ 789 /* khubd and related activity won't re-trigger */
720 hub->quiescing = 1; 790 hub->quiescing = 1;
721 791
@@ -1099,6 +1169,7 @@ descriptor_error:
1099 hub->intfdev = &intf->dev; 1169 hub->intfdev = &intf->dev;
1100 hub->hdev = hdev; 1170 hub->hdev = hdev;
1101 INIT_DELAYED_WORK(&hub->leds, led_work); 1171 INIT_DELAYED_WORK(&hub->leds, led_work);
1172 INIT_DELAYED_WORK(&hub->init_work, NULL);
1102 usb_get_intf(intf); 1173 usb_get_intf(intf);
1103 1174
1104 usb_set_intfdata (intf, hub); 1175 usb_set_intfdata (intf, hub);
@@ -3035,7 +3106,7 @@ static void hub_events(void)
3035 i); 3106 i);
3036 clear_port_feature(hdev, i, 3107 clear_port_feature(hdev, i,
3037 USB_PORT_FEAT_C_OVER_CURRENT); 3108 USB_PORT_FEAT_C_OVER_CURRENT);
3038 hub_power_on(hub); 3109 hub_power_on(hub, true);
3039 } 3110 }
3040 3111
3041 if (portchange & USB_PORT_STAT_C_RESET) { 3112 if (portchange & USB_PORT_STAT_C_RESET) {
@@ -3070,7 +3141,7 @@ static void hub_events(void)
3070 dev_dbg (hub_dev, "overcurrent change\n"); 3141 dev_dbg (hub_dev, "overcurrent change\n");
3071 msleep(500); /* Cool down */ 3142 msleep(500); /* Cool down */
3072 clear_hub_feature(hdev, C_HUB_OVER_CURRENT); 3143 clear_hub_feature(hdev, C_HUB_OVER_CURRENT);
3073 hub_power_on(hub); 3144 hub_power_on(hub, true);
3074 } 3145 }
3075 } 3146 }
3076 3147