Commit b4f93012 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] ehci, async idle timout

One more patch:  this turns off async schedule processing
if there are no control or bulk transactions for a while
(currently HZ/3).  Consequence:  no PCI accesses unless
there's work to do.  (And a FIXME comment is gone!)
parent dcd37e86
...@@ -111,6 +111,7 @@ ...@@ -111,6 +111,7 @@
#define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_MULT_TT 1
#define EHCI_WATCHDOG_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ #define EHCI_WATCHDOG_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
#define EHCI_ASYNC_JIFFIES (HZ/3) /* async idle timeout */
/* Initial IRQ latency: lower than default */ /* Initial IRQ latency: lower than default */
static int log2_irq_thresh = 0; // 0 to 6 static int log2_irq_thresh = 0; // 0 to 6
...@@ -247,9 +248,14 @@ static void ehci_watchdog (unsigned long param) ...@@ -247,9 +248,14 @@ static void ehci_watchdog (unsigned long param)
struct ehci_hcd *ehci = (struct ehci_hcd *) param; struct ehci_hcd *ehci = (struct ehci_hcd *) param;
unsigned long flags; unsigned long flags;
/* guard against lost IAA, which wedges everything */
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
/* guard against lost IAA, which wedges everything */
ehci_irq (&ehci->hcd); ehci_irq (&ehci->hcd);
/* unlink the last qh after it's idled a while */
if (ehci->async_idle) {
start_unlink_async (ehci, ehci->async);
ehci->async_idle = 0;
}
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
} }
......
...@@ -736,6 +736,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -736,6 +736,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
} }
qh->qh_state = QH_STATE_LINKED; qh->qh_state = QH_STATE_LINKED;
/* qtd completions reported later by interrupt */ /* qtd completions reported later by interrupt */
ehci->async_idle = 0;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1004,16 +1006,18 @@ scan_async (struct ehci_hcd *ehci, unsigned long flags) ...@@ -1004,16 +1006,18 @@ scan_async (struct ehci_hcd *ehci, unsigned long flags)
} }
/* unlink idle entries, reducing HC PCI usage as /* unlink idle entries, reducing HC PCI usage as
* well as HCD schedule-scanning costs * well as HCD schedule-scanning costs. removing
* the last qh is deferred, since it's costly.
*/ */
if (list_empty (&qh->qtd_list) && !ehci->reclaim) { if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
if (qh->qh_next.qh != qh) { if (qh->qh_next.qh != qh) {
// dbg ("irq/empty"); // dbg ("irq/empty");
start_unlink_async (ehci, qh); start_unlink_async (ehci, qh);
} else { } else if (!timer_pending (&ehci->watchdog)) {
// FIXME: arrange to stop /* can't use IAA for last entry */
// after it's been idle a while. ehci->async_idle = 1;
// stop/restart isn't free... mod_timer (&ehci->watchdog,
jiffies + EHCI_ASYNC_JIFFIES);
} }
} }
qh = qh->qh_next.qh; qh = qh->qh_next.qh;
......
...@@ -39,7 +39,8 @@ struct ehci_hcd { /* one per controller */ ...@@ -39,7 +39,8 @@ struct ehci_hcd { /* one per controller */
/* async schedule support */ /* async schedule support */
struct ehci_qh *async; struct ehci_qh *async;
struct ehci_qh *reclaim; struct ehci_qh *reclaim;
int reclaim_ready; int reclaim_ready : 1,
async_idle : 1;
/* periodic schedule support */ /* periodic schedule support */
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */ #define DEFAULT_I_TDPS 1024 /* some HCs can do less */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment