aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2005-04-21 15:56:37 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-06-27 17:43:45 -0400
commitd5926ae7a827bdd06b588ffbc56fd4525cd9214a (patch)
treee5c63a32abfff5d504e4201d93ab593427c5e810
parent02597d2deec2a3de0e2b52c1f83904b65626a0d5 (diff)
[PATCH] usbcore support for root-hub IRQ instead of polling
This is a revised version of an earlier patch to add support to usbcore for driving root hubs by interrupts rather than polling. There's a temporary flag added to struct usb_hcd, marking devices whose drivers are aware of the new mechanism. By default that flag doesn't get set so drivers will continue to see the same polling behavior as before. This way we can convert the HCDs one by one to use interrupt-based event reporting, and the temporary flag can be removed when they're all done. Also included is a small change to the hcd_disable_endpoint routine. Although endpoints normally shouldn't be disabled while a controller is suspended, it's legal to do so when the controller's driver is being rmmod'ed. Lastly the patch adds a new callback, .hub_irq_enable, for use by HCDs where the root hub's port-change interrupts are level-triggered rather than edge-triggered. The callback is invoked each time khubd has finished processing a root hub, to let the HCD know that the interrupt can safely be re-enabled. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/hcd.c207
-rw-r--r--drivers/usb/core/hcd.h15
-rw-r--r--drivers/usb/core/hub.c5
3 files changed, 140 insertions, 87 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 0da23732e807..1180c157b717 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -519,119 +519,120 @@ error:
519/*-------------------------------------------------------------------------*/ 519/*-------------------------------------------------------------------------*/
520 520
521/* 521/*
522 * Root Hub interrupt transfers are synthesized with a timer. 522 * Root Hub interrupt transfers are polled using a timer if the
523 * Completions are called in_interrupt() but not in_irq(). 523 * driver requests it; otherwise the driver is responsible for
524 * calling usb_hcd_poll_rh_status() when an event occurs.
524 * 525 *
525 * Note: some root hubs (including common UHCI based designs) can't 526 * Completions are called in_interrupt(), but they may or may not
526 * correctly issue port change IRQs. They're the ones that _need_ a 527 * be in_irq().
527 * timer; most other root hubs don't. Some systems could save a
528 * lot of battery power by eliminating these root hub timer IRQs.
529 */ 528 */
529void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
530{
531 struct urb *urb;
532 int length;
533 unsigned long flags;
534 char buffer[4]; /* Any root hubs with > 31 ports? */
530 535
531static void rh_report_status (unsigned long ptr); 536 if (!hcd->uses_new_polling && !hcd->status_urb)
537 return;
532 538
533static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) 539 length = hcd->driver->hub_status_data(hcd, buffer);
534{ 540 if (length > 0) {
535 int len = 1 + (urb->dev->maxchild / 8);
536 541
537 /* rh_timer protected by hcd_data_lock */ 542 /* try to complete the status urb */
538 if (hcd->rh_timer.data || urb->transfer_buffer_length < len) { 543 local_irq_save (flags);
539 dev_dbg (hcd->self.controller, 544 spin_lock(&hcd_root_hub_lock);
540 "not queuing rh status urb, stat %d\n", 545 urb = hcd->status_urb;
541 urb->status); 546 if (urb) {
542 return -EINVAL; 547 spin_lock(&urb->lock);
548 if (urb->status == -EINPROGRESS) {
549 hcd->poll_pending = 0;
550 hcd->status_urb = NULL;
551 urb->status = 0;
552 urb->hcpriv = NULL;
553 urb->actual_length = length;
554 memcpy(urb->transfer_buffer, buffer, length);
555 } else /* urb has been unlinked */
556 length = 0;
557 spin_unlock(&urb->lock);
558 } else
559 length = 0;
560 spin_unlock(&hcd_root_hub_lock);
561
562 /* local irqs are always blocked in completions */
563 if (length > 0)
564 usb_hcd_giveback_urb (hcd, urb, NULL);
565 else
566 hcd->poll_pending = 1;
567 local_irq_restore (flags);
543 } 568 }
544 569
545 init_timer (&hcd->rh_timer); 570 /* The USB 2.0 spec says 256 ms. This is close enough and won't
546 hcd->rh_timer.function = rh_report_status; 571 * exceed that limit if HZ is 100. */
547 hcd->rh_timer.data = (unsigned long) urb; 572 if (hcd->uses_new_polling ? hcd->poll_rh :
548 /* USB 2.0 spec says 256msec; this is close enough */ 573 (length == 0 && hcd->status_urb != NULL))
549 hcd->rh_timer.expires = jiffies + HZ/4; 574 mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250));
550 add_timer (&hcd->rh_timer);
551 urb->hcpriv = hcd; /* nonzero to indicate it's queued */
552 return 0;
553} 575}
576EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status);
554 577
555/* timer callback */ 578/* timer callback */
579static void rh_timer_func (unsigned long _hcd)
580{
581 usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);
582}
583
584/*-------------------------------------------------------------------------*/
556 585
557static void rh_report_status (unsigned long ptr) 586static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
558{ 587{
559 struct urb *urb; 588 int retval;
560 struct usb_hcd *hcd;
561 int length = 0;
562 unsigned long flags; 589 unsigned long flags;
590 int len = 1 + (urb->dev->maxchild / 8);
563 591
564 urb = (struct urb *) ptr; 592 spin_lock_irqsave (&hcd_root_hub_lock, flags);
565 local_irq_save (flags); 593 if (urb->status != -EINPROGRESS) /* already unlinked */
566 spin_lock (&urb->lock); 594 retval = urb->status;
595 else if (hcd->status_urb || urb->transfer_buffer_length < len) {
596 dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
597 retval = -EINVAL;
598 } else {
599 hcd->status_urb = urb;
600 urb->hcpriv = hcd; /* indicate it's queued */
567 601
568 /* do nothing if the urb's been unlinked */ 602 if (!hcd->uses_new_polling)
569 if (!urb->dev 603 mod_timer (&hcd->rh_timer, jiffies +
570 || urb->status != -EINPROGRESS 604 msecs_to_jiffies(250));
571 || (hcd = urb->dev->bus->hcpriv) == NULL) {
572 spin_unlock (&urb->lock);
573 local_irq_restore (flags);
574 return;
575 }
576 605
577 /* complete the status urb, or retrigger the timer */ 606 /* If a status change has already occurred, report it ASAP */
578 spin_lock (&hcd_data_lock); 607 else if (hcd->poll_pending)
579 if (urb->dev->state == USB_STATE_CONFIGURED) { 608 mod_timer (&hcd->rh_timer, jiffies);
580 length = hcd->driver->hub_status_data ( 609 retval = 0;
581 hcd, urb->transfer_buffer);
582 if (length > 0) {
583 hcd->rh_timer.data = 0;
584 urb->actual_length = length;
585 urb->status = 0;
586 urb->hcpriv = NULL;
587 } else
588 mod_timer (&hcd->rh_timer, jiffies + HZ/4);
589 } 610 }
590 spin_unlock (&hcd_data_lock); 611 spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
591 spin_unlock (&urb->lock); 612 return retval;
592
593 /* local irqs are always blocked in completions */
594 if (length > 0)
595 usb_hcd_giveback_urb (hcd, urb, NULL);
596 local_irq_restore (flags);
597} 613}
598 614
599/*-------------------------------------------------------------------------*/
600
601static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) 615static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
602{ 616{
603 if (usb_pipeint (urb->pipe)) { 617 if (usb_pipeint (urb->pipe))
604 int retval; 618 return rh_queue_status (hcd, urb);
605 unsigned long flags;
606
607 spin_lock_irqsave (&hcd_data_lock, flags);
608 retval = rh_status_urb (hcd, urb);
609 spin_unlock_irqrestore (&hcd_data_lock, flags);
610 return retval;
611 }
612 if (usb_pipecontrol (urb->pipe)) 619 if (usb_pipecontrol (urb->pipe))
613 return rh_call_control (hcd, urb); 620 return rh_call_control (hcd, urb);
614 else 621 return -EINVAL;
615 return -EINVAL;
616} 622}
617 623
618/*-------------------------------------------------------------------------*/ 624/*-------------------------------------------------------------------------*/
619 625
626/* Asynchronous unlinks of root-hub control URBs are legal, but they
627 * don't do anything. Status URB unlinks must be made in process context
628 * with interrupts enabled.
629 */
620static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) 630static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
621{ 631{
622 unsigned long flags; 632 if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
623 633 if (in_interrupt())
624 /* note: always a synchronous unlink */ 634 return 0; /* nothing to do */
625 if ((unsigned long) urb == hcd->rh_timer.data) {
626 del_timer_sync (&hcd->rh_timer);
627 hcd->rh_timer.data = 0;
628
629 local_irq_save (flags);
630 urb->hcpriv = NULL;
631 usb_hcd_giveback_urb (hcd, urb, NULL);
632 local_irq_restore (flags);
633 635
634 } else if (usb_pipeendpoint(urb->pipe) == 0) {
635 spin_lock_irq(&urb->lock); /* from usb_kill_urb */ 636 spin_lock_irq(&urb->lock); /* from usb_kill_urb */
636 ++urb->reject; 637 ++urb->reject;
637 spin_unlock_irq(&urb->lock); 638 spin_unlock_irq(&urb->lock);
@@ -642,8 +643,22 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
642 spin_lock_irq(&urb->lock); 643 spin_lock_irq(&urb->lock);
643 --urb->reject; 644 --urb->reject;
644 spin_unlock_irq(&urb->lock); 645 spin_unlock_irq(&urb->lock);
645 } else 646
646 return -EINVAL; 647 } else { /* Status URB */
648 if (!hcd->uses_new_polling)
649 del_timer_sync (&hcd->rh_timer);
650 local_irq_disable ();
651 spin_lock (&hcd_root_hub_lock);
652 if (urb == hcd->status_urb) {
653 hcd->status_urb = NULL;
654 urb->hcpriv = NULL;
655 } else
656 urb = NULL; /* wasn't fully queued */
657 spin_unlock (&hcd_root_hub_lock);
658 if (urb)
659 usb_hcd_giveback_urb (hcd, urb, NULL);
660 local_irq_enable ();
661 }
647 662
648 return 0; 663 return 0;
649} 664}
@@ -885,6 +900,16 @@ int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd)
885} 900}
886EXPORT_SYMBOL_GPL(usb_hcd_register_root_hub); 901EXPORT_SYMBOL_GPL(usb_hcd_register_root_hub);
887 902
903void usb_enable_root_hub_irq (struct usb_bus *bus)
904{
905 struct usb_hcd *hcd;
906
907 hcd = container_of (bus, struct usb_hcd, self);
908 if (hcd->driver->hub_irq_enable && !hcd->poll_rh &&
909 hcd->state != HC_STATE_HALT)
910 hcd->driver->hub_irq_enable (hcd);
911}
912
888 913
889/*-------------------------------------------------------------------------*/ 914/*-------------------------------------------------------------------------*/
890 915
@@ -1348,7 +1373,8 @@ hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep)
1348 1373
1349 hcd = udev->bus->hcpriv; 1374 hcd = udev->bus->hcpriv;
1350 1375
1351 WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT); 1376 WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT &&
1377 udev->state != USB_STATE_NOTATTACHED);
1352 1378
1353 local_irq_disable (); 1379 local_irq_disable ();
1354 1380
@@ -1612,6 +1638,8 @@ void usb_hc_died (struct usb_hcd *hcd)
1612 1638
1613 spin_lock_irqsave (&hcd_root_hub_lock, flags); 1639 spin_lock_irqsave (&hcd_root_hub_lock, flags);
1614 if (hcd->rh_registered) { 1640 if (hcd->rh_registered) {
1641 hcd->poll_rh = 0;
1642 del_timer(&hcd->rh_timer);
1615 1643
1616 /* make khubd clean up old urbs and devices */ 1644 /* make khubd clean up old urbs and devices */
1617 usb_set_device_state (hcd->self.root_hub, 1645 usb_set_device_state (hcd->self.root_hub,
@@ -1665,6 +1693,8 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
1665 hcd->self.bus_name = bus_name; 1693 hcd->self.bus_name = bus_name;
1666 1694
1667 init_timer(&hcd->rh_timer); 1695 init_timer(&hcd->rh_timer);
1696 hcd->rh_timer.function = rh_timer_func;
1697 hcd->rh_timer.data = (unsigned long) hcd;
1668 1698
1669 hcd->driver = driver; 1699 hcd->driver = driver;
1670 hcd->product_desc = (driver->product_desc) ? driver->product_desc : 1700 hcd->product_desc = (driver->product_desc) ? driver->product_desc :
@@ -1748,6 +1778,8 @@ int usb_add_hcd(struct usb_hcd *hcd,
1748 goto err3; 1778 goto err3;
1749 } 1779 }
1750 1780
1781 if (hcd->uses_new_polling && hcd->poll_rh)
1782 usb_hcd_poll_rh_status(hcd);
1751 return retval; 1783 return retval;
1752 1784
1753 err3: 1785 err3:
@@ -1782,6 +1814,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
1782 spin_unlock_irq (&hcd_root_hub_lock); 1814 spin_unlock_irq (&hcd_root_hub_lock);
1783 usb_disconnect(&hcd->self.root_hub); 1815 usb_disconnect(&hcd->self.root_hub);
1784 1816
1817 hcd->poll_rh = 0;
1818 del_timer_sync(&hcd->rh_timer);
1819
1785 hcd->driver->stop(hcd); 1820 hcd->driver->stop(hcd);
1786 hcd->state = HC_STATE_HALT; 1821 hcd->state = HC_STATE_HALT;
1787 1822
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 325a51656c3f..ac5752778e39 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -65,7 +65,8 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
65 const char *product_desc; /* product/vendor string */ 65 const char *product_desc; /* product/vendor string */
66 char irq_descr[24]; /* driver + bus # */ 66 char irq_descr[24]; /* driver + bus # */
67 67
68 struct timer_list rh_timer; /* drives root hub */ 68 struct timer_list rh_timer; /* drives root-hub polling */
69 struct urb *status_urb; /* the current status urb */
69 70
70 /* 71 /*
71 * hardware info/state 72 * hardware info/state
@@ -76,6 +77,12 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
76 unsigned remote_wakeup:1;/* sw should use wakeup? */ 77 unsigned remote_wakeup:1;/* sw should use wakeup? */
77 unsigned rh_registered:1;/* is root hub registered? */ 78 unsigned rh_registered:1;/* is root hub registered? */
78 79
80 /* The next flag is a stopgap, to be removed when all the HCDs
81 * support the new root-hub polling mechanism. */
82 unsigned uses_new_polling:1;
83 unsigned poll_rh:1; /* poll for rh status? */
84 unsigned poll_pending:1; /* status has changed? */
85
79 int irq; /* irq allocated */ 86 int irq; /* irq allocated */
80 void __iomem *regs; /* device memory/io */ 87 void __iomem *regs; /* device memory/io */
81 u64 rsrc_start; /* memory/io resource start */ 88 u64 rsrc_start; /* memory/io resource start */
@@ -207,6 +214,8 @@ struct hc_driver {
207 int (*hub_suspend)(struct usb_hcd *); 214 int (*hub_suspend)(struct usb_hcd *);
208 int (*hub_resume)(struct usb_hcd *); 215 int (*hub_resume)(struct usb_hcd *);
209 int (*start_port_reset)(struct usb_hcd *, unsigned port_num); 216 int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
217 void (*hub_irq_enable)(struct usb_hcd *);
218 /* Needed only if port-change IRQs are level-triggered */
210}; 219};
211 220
212extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs); 221extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
@@ -243,7 +252,9 @@ void hcd_buffer_free (struct usb_bus *bus, size_t size,
243 252
244/* generic bus glue, needed for host controllers that don't use PCI */ 253/* generic bus glue, needed for host controllers that don't use PCI */
245extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r); 254extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
255
246extern void usb_hc_died (struct usb_hcd *hcd); 256extern void usb_hc_died (struct usb_hcd *hcd);
257extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
247 258
248/* -------------------------------------------------------------------------- */ 259/* -------------------------------------------------------------------------- */
249 260
@@ -360,6 +371,8 @@ extern wait_queue_head_t usb_kill_urb_queue;
360extern struct usb_bus *usb_bus_get (struct usb_bus *bus); 371extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
361extern void usb_bus_put (struct usb_bus *bus); 372extern void usb_bus_put (struct usb_bus *bus);
362 373
374extern void usb_enable_root_hub_irq (struct usb_bus *bus);
375
363extern int usb_find_interface_driver (struct usb_device *dev, 376extern int usb_find_interface_driver (struct usb_device *dev,
364 struct usb_interface *interface); 377 struct usb_interface *interface);
365 378
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index a8d879a85d04..6d1a330d577b 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2787,6 +2787,11 @@ static void hub_events(void)
2787 2787
2788 hub->activating = 0; 2788 hub->activating = 0;
2789 2789
2790 /* If this is a root hub, tell the HCD it's okay to
2791 * re-enable port-change interrupts now. */
2792 if (!hdev->parent)
2793 usb_enable_root_hub_irq(hdev->bus);
2794
2790loop: 2795loop:
2791 usb_unlock_device(hdev); 2796 usb_unlock_device(hdev);
2792 usb_put_intf(intf); 2797 usb_put_intf(intf);