Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
d5926ae7 02597d2d

+145 -92
+126 -91
drivers/usb/core/hcd.c
··· 519 519 /*-------------------------------------------------------------------------*/ 520 520 521 521 /* 522 - * Root Hub interrupt transfers are synthesized with a timer. 523 - * Completions are called in_interrupt() but not in_irq(). 522 + * Root Hub interrupt transfers are polled using a timer if the 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 - * correctly issue port change IRQs. They're the ones that _need_ a 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. 526 + * Completions are called in_interrupt(), but they may or may not 527 + * be in_irq(). 529 528 */ 530 - 531 - static void rh_report_status (unsigned long ptr); 532 - 533 - static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) 534 - { 535 - int len = 1 + (urb->dev->maxchild / 8); 536 - 537 - /* rh_timer protected by hcd_data_lock */ 538 - if (hcd->rh_timer.data || urb->transfer_buffer_length < len) { 539 - dev_dbg (hcd->self.controller, 540 - "not queuing rh status urb, stat %d\n", 541 - urb->status); 542 - return -EINVAL; 543 - } 544 - 545 - init_timer (&hcd->rh_timer); 546 - hcd->rh_timer.function = rh_report_status; 547 - hcd->rh_timer.data = (unsigned long) urb; 548 - /* USB 2.0 spec says 256msec; this is close enough */ 549 - hcd->rh_timer.expires = jiffies + HZ/4; 550 - add_timer (&hcd->rh_timer); 551 - urb->hcpriv = hcd; /* nonzero to indicate it's queued */ 552 - return 0; 553 - } 554 - 555 - /* timer callback */ 556 - 557 - static void rh_report_status (unsigned long ptr) 529 + void usb_hcd_poll_rh_status(struct usb_hcd *hcd) 558 530 { 559 531 struct urb *urb; 560 - struct usb_hcd *hcd; 561 - int length = 0; 532 + int length; 562 533 unsigned long flags; 534 + char buffer[4]; /* Any root hubs with > 31 ports? */ 563 535 564 - urb = (struct urb *) ptr; 565 - local_irq_save (flags); 566 - spin_lock (&urb->lock); 567 - 568 - /* do nothing if the urb's been unlinked */ 569 - if (!urb->dev 570 - || urb->status != -EINPROGRESS 571 - || (hcd = urb->dev->bus->hcpriv) == NULL) { 572 - spin_unlock (&urb->lock); 573 - local_irq_restore (flags); 536 + if (!hcd->uses_new_polling && !hcd->status_urb) 574 537 return; 575 - } 576 538 577 - /* complete the status urb, or retrigger the timer */ 578 - spin_lock (&hcd_data_lock); 579 - if (urb->dev->state == USB_STATE_CONFIGURED) { 580 - length = hcd->driver->hub_status_data ( 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; 539 + length = hcd->driver->hub_status_data(hcd, buffer); 540 + if (length > 0) { 541 + 542 + /* try to complete the status urb */ 543 + local_irq_save (flags); 544 + spin_lock(&hcd_root_hub_lock); 545 + urb = hcd->status_urb; 546 + if (urb) { 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); 587 558 } else 588 - mod_timer (&hcd->rh_timer, jiffies + HZ/4); 589 - } 590 - spin_unlock (&hcd_data_lock); 591 - spin_unlock (&urb->lock); 559 + length = 0; 560 + spin_unlock(&hcd_root_hub_lock); 592 561 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); 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); 568 + } 569 + 570 + /* The USB 2.0 spec says 256 ms. This is close enough and won't 571 + * exceed that limit if HZ is 100. */ 572 + if (hcd->uses_new_polling ? hcd->poll_rh : 573 + (length == 0 && hcd->status_urb != NULL)) 574 + mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250)); 575 + } 576 + EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status); 577 + 578 + /* timer callback */ 579 + static void rh_timer_func (unsigned long _hcd) 580 + { 581 + usb_hcd_poll_rh_status((struct usb_hcd *) _hcd); 597 582 } 598 583 599 584 /*-------------------------------------------------------------------------*/ 585 + 586 + static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb) 587 + { 588 + int retval; 589 + unsigned long flags; 590 + int len = 1 + (urb->dev->maxchild / 8); 591 + 592 + spin_lock_irqsave (&hcd_root_hub_lock, flags); 593 + if (urb->status != -EINPROGRESS) /* already unlinked */ 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 */ 601 + 602 + if (!hcd->uses_new_polling) 603 + mod_timer (&hcd->rh_timer, jiffies + 604 + msecs_to_jiffies(250)); 605 + 606 + /* If a status change has already occurred, report it ASAP */ 607 + else if (hcd->poll_pending) 608 + mod_timer (&hcd->rh_timer, jiffies); 609 + retval = 0; 610 + } 611 + spin_unlock_irqrestore (&hcd_root_hub_lock, flags); 612 + return retval; 613 + } 600 614 601 615 static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) 602 616 { 603 - if (usb_pipeint (urb->pipe)) { 604 - int retval; 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 - } 617 + if (usb_pipeint (urb->pipe)) 618 + return rh_queue_status (hcd, urb); 612 619 if (usb_pipecontrol (urb->pipe)) 613 620 return rh_call_control (hcd, urb); 614 - else 615 - return -EINVAL; 621 + 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 + */ 620 630 static 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 */ 633 + if (in_interrupt()) 634 + return 0; /* nothing to do */ 623 635 624 - /* note: always a synchronous unlink */ 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 - 634 - } else if (usb_pipeendpoint(urb->pipe) == 0) { 635 636 spin_lock_irq(&urb->lock); /* from usb_kill_urb */ 636 637 ++urb->reject; 637 638 spin_unlock_irq(&urb->lock); ··· 643 642 spin_lock_irq(&urb->lock); 644 643 --urb->reject; 645 644 spin_unlock_irq(&urb->lock); 646 - } else 647 - return -EINVAL; 645 + 646 + } else { /* Status URB */ 647 + if (!hcd->uses_new_polling) 648 + del_timer_sync (&hcd->rh_timer); 649 + local_irq_disable (); 650 + spin_lock (&hcd_root_hub_lock); 651 + if (urb == hcd->status_urb) { 652 + hcd->status_urb = NULL; 653 + urb->hcpriv = NULL; 654 + } else 655 + urb = NULL; /* wasn't fully queued */ 656 + spin_unlock (&hcd_root_hub_lock); 657 + if (urb) 658 + usb_hcd_giveback_urb (hcd, urb, NULL); 659 + local_irq_enable (); 660 + } 648 661 649 662 return 0; 650 663 } ··· 899 884 return retval; 900 885 } 901 886 EXPORT_SYMBOL_GPL(usb_hcd_register_root_hub); 887 + 888 + void usb_enable_root_hub_irq (struct usb_bus *bus) 889 + { 890 + struct usb_hcd *hcd; 891 + 892 + hcd = container_of (bus, struct usb_hcd, self); 893 + if (hcd->driver->hub_irq_enable && !hcd->poll_rh && 894 + hcd->state != HC_STATE_HALT) 895 + hcd->driver->hub_irq_enable (hcd); 896 + } 902 897 903 898 904 899 /*-------------------------------------------------------------------------*/ ··· 1373 1348 1374 1349 hcd = udev->bus->hcpriv; 1375 1350 1376 - WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT); 1351 + WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT && 1352 + udev->state != USB_STATE_NOTATTACHED); 1377 1353 1378 1354 local_irq_disable (); 1379 1355 ··· 1638 1612 1639 1613 spin_lock_irqsave (&hcd_root_hub_lock, flags); 1640 1614 if (hcd->rh_registered) { 1615 + hcd->poll_rh = 0; 1616 + del_timer(&hcd->rh_timer); 1641 1617 1642 1618 /* make khubd clean up old urbs and devices */ 1643 1619 usb_set_device_state (hcd->self.root_hub, ··· 1693 1665 hcd->self.bus_name = bus_name; 1694 1666 1695 1667 init_timer(&hcd->rh_timer); 1668 + hcd->rh_timer.function = rh_timer_func; 1669 + hcd->rh_timer.data = (unsigned long) hcd; 1696 1670 1697 1671 hcd->driver = driver; 1698 1672 hcd->product_desc = (driver->product_desc) ? driver->product_desc : ··· 1778 1748 goto err3; 1779 1749 } 1780 1750 1751 + if (hcd->uses_new_polling && hcd->poll_rh) 1752 + usb_hcd_poll_rh_status(hcd); 1781 1753 return retval; 1782 1754 1783 1755 err3: ··· 1813 1781 hcd->rh_registered = 0; 1814 1782 spin_unlock_irq (&hcd_root_hub_lock); 1815 1783 usb_disconnect(&hcd->self.root_hub); 1784 + 1785 + hcd->poll_rh = 0; 1786 + del_timer_sync(&hcd->rh_timer); 1816 1787 1817 1788 hcd->driver->stop(hcd); 1818 1789 hcd->state = HC_STATE_HALT;
+14 -1
drivers/usb/core/hcd.h
··· 65 65 const char *product_desc; /* product/vendor string */ 66 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 72 * hardware info/state ··· 76 75 unsigned can_wakeup:1; /* hw supports wakeup? */ 77 76 unsigned remote_wakeup:1;/* sw should use wakeup? */ 78 77 unsigned rh_registered:1;/* is root hub registered? */ 78 + 79 + /* The next flag is a stopgap, to be removed when all the HCDs 80 + * support the new root-hub polling mechanism. */ 81 + unsigned uses_new_polling:1; 82 + unsigned poll_rh:1; /* poll for rh status? */ 83 + unsigned poll_pending:1; /* status has changed? */ 79 84 80 85 int irq; /* irq allocated */ 81 86 void __iomem *regs; /* device memory/io */ ··· 214 207 int (*hub_suspend)(struct usb_hcd *); 215 208 int (*hub_resume)(struct usb_hcd *); 216 209 int (*start_port_reset)(struct usb_hcd *, unsigned port_num); 210 + void (*hub_irq_enable)(struct usb_hcd *); 211 + /* Needed only if port-change IRQs are level-triggered */ 217 212 }; 218 213 219 214 extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs); ··· 252 243 253 244 /* generic bus glue, needed for host controllers that don't use PCI */ 254 245 extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r); 246 + 255 247 extern void usb_hc_died (struct usb_hcd *hcd); 248 + extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd); 256 249 257 250 /* -------------------------------------------------------------------------- */ 258 251 ··· 370 359 371 360 extern struct usb_bus *usb_bus_get (struct usb_bus *bus); 372 361 extern void usb_bus_put (struct usb_bus *bus); 362 + 363 + extern void usb_enable_root_hub_irq (struct usb_bus *bus); 373 364 374 365 extern int usb_find_interface_driver (struct usb_device *dev, 375 366 struct usb_interface *interface);
+5
drivers/usb/core/hub.c
··· 2787 2787 2788 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 + 2790 2795 loop: 2791 2796 usb_unlock_device(hdev); 2792 2797 usb_put_intf(intf);