aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ohci-hcd.c
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2006-08-04 14:31:55 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-09-27 14:58:48 -0400
commitd413984ae936fad46678403b38d79c595e5aaafe (patch)
treef494a450d7289d941e3ca2b2e33bfacc29cac024 /drivers/usb/host/ohci-hcd.c
parent06afff00bcab0e384afbef70194fd3469532abdf (diff)
USB: OHCI avoids root hub timer polling
This teaches OHCI to use the root hub status change (RHSC) IRQ, bypassing root hub timers most of the time and switching over to the "new" root hub polling scheme. It's complicated by the fact that implementations of OHCI trigger and ack that IRQ differently (the spec is vague there). Avoiding root hub timers helps mechanisms like "dynamic tick" leave the CPU in lowpower modes for longer intervals. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ohci-hcd.c')
-rw-r--r--drivers/usb/host/ohci-hcd.c41
1 files changed, 32 insertions, 9 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 94d8cf4b36c1..0684f57c14a0 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -101,7 +101,7 @@
101 101
102#include "../core/hcd.h" 102#include "../core/hcd.h"
103 103
104#define DRIVER_VERSION "2005 April 22" 104#define DRIVER_VERSION "2006 August 04"
105#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell" 105#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
106#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver" 106#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
107 107
@@ -110,9 +110,10 @@
110#undef OHCI_VERBOSE_DEBUG /* not always helpful */ 110#undef OHCI_VERBOSE_DEBUG /* not always helpful */
111 111
112/* For initializing controller (mask in an HCFS mode too) */ 112/* For initializing controller (mask in an HCFS mode too) */
113#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR 113#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
114#define OHCI_INTR_INIT \ 114#define OHCI_INTR_INIT \
115 (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH) 115 (OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_UE \
116 | OHCI_INTR_RD | OHCI_INTR_WDH)
116 117
117#ifdef __hppa__ 118#ifdef __hppa__
118/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */ 119/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
@@ -128,6 +129,8 @@
128 129
129static const char hcd_name [] = "ohci_hcd"; 130static const char hcd_name [] = "ohci_hcd";
130 131
132#define STATECHANGE_DELAY msecs_to_jiffies(300)
133
131#include "ohci.h" 134#include "ohci.h"
132 135
133static void ohci_dump (struct ohci_hcd *ohci, int verbose); 136static void ohci_dump (struct ohci_hcd *ohci, int verbose);
@@ -446,7 +449,6 @@ static int ohci_init (struct ohci_hcd *ohci)
446 449
447 disable (ohci); 450 disable (ohci);
448 ohci->regs = hcd->regs; 451 ohci->regs = hcd->regs;
449 ohci->next_statechange = jiffies;
450 452
451 /* REVISIT this BIOS handshake is now moved into PCI "quirks", and 453 /* REVISIT this BIOS handshake is now moved into PCI "quirks", and
452 * was never needed for most non-PCI systems ... remove the code? 454 * was never needed for most non-PCI systems ... remove the code?
@@ -637,10 +639,14 @@ retry:
637 return -EOVERFLOW; 639 return -EOVERFLOW;
638 } 640 }
639 641
640 /* start controller operations */ 642 /* use rhsc irqs after khubd is fully initialized */
643 hcd->poll_rh = 1;
644 hcd->uses_new_polling = 1;
645
646 /* start controller operations */
641 ohci->hc_control &= OHCI_CTRL_RWC; 647 ohci->hc_control &= OHCI_CTRL_RWC;
642 ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; 648 ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
643 ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); 649 ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
644 hcd->state = HC_STATE_RUNNING; 650 hcd->state = HC_STATE_RUNNING;
645 651
646 /* wake on ConnectStatusChange, matching external hubs */ 652 /* wake on ConnectStatusChange, matching external hubs */
@@ -648,7 +654,7 @@ retry:
648 654
649 /* Choose the interrupts we care about now, others later on demand */ 655 /* Choose the interrupts we care about now, others later on demand */
650 mask = OHCI_INTR_INIT; 656 mask = OHCI_INTR_INIT;
651 ohci_writel (ohci, mask, &ohci->regs->intrstatus); 657 ohci_writel (ohci, ~0, &ohci->regs->intrstatus);
652 ohci_writel (ohci, mask, &ohci->regs->intrenable); 658 ohci_writel (ohci, mask, &ohci->regs->intrenable);
653 659
654 /* handle root hub init quirks ... */ 660 /* handle root hub init quirks ... */
@@ -672,6 +678,7 @@ retry:
672 // flush those writes 678 // flush those writes
673 (void) ohci_readl (ohci, &ohci->regs->control); 679 (void) ohci_readl (ohci, &ohci->regs->control);
674 680
681 ohci->next_statechange = jiffies + STATECHANGE_DELAY;
675 spin_unlock_irq (&ohci->lock); 682 spin_unlock_irq (&ohci->lock);
676 683
677 // POTPGT delay is bits 24-31, in 2 ms units. 684 // POTPGT delay is bits 24-31, in 2 ms units.
@@ -709,7 +716,23 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
709 /* interrupt for some other device? */ 716 /* interrupt for some other device? */
710 } else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) { 717 } else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) {
711 return IRQ_NOTMINE; 718 return IRQ_NOTMINE;
712 } 719 }
720
721 /* NOTE: vendors didn't always make the same implementation
722 * choices for RHSC. Sometimes it triggers on an edge (like
723 * setting and maybe clearing a port status change bit); and
724 * it's level-triggered on other silicon, active until khubd
725 * clears all active port status change bits. Poll by timer
726 * til it's fully debounced and the difference won't matter.
727 */
728 if (ints & OHCI_INTR_RHSC) {
729 ohci_vdbg (ohci, "rhsc\n");
730 ohci_writel (ohci, OHCI_INTR_RHSC, &regs->intrdisable);
731 hcd->poll_rh = 1;
732 ohci->next_statechange = jiffies + STATECHANGE_DELAY;
733 ohci_writel (ohci, OHCI_INTR_RHSC, &regs->intrstatus);
734 usb_hcd_poll_rh_status(hcd);
735 }
713 736
714 if (ints & OHCI_INTR_UE) { 737 if (ints & OHCI_INTR_UE) {
715 disable (ohci); 738 disable (ohci);