Discussion:
[PATCH] EHCI: add separate IAA watchdog timer
Alan Stern
2007-12-11 21:05:30 UTC
Permalink
This patch (as1028) was mostly written by David Brownell; I made only
a few changes (extra log info and a small bug fix -- which might
account for why David's version had to be reverted). It adds a new
watchdog timer to the ehci-hcd driver to be used exclusively for
detecting lost or missing IAA notifications.

Previously a shared timer had been used, which may have led to some
problems as reported by Christian Hoffmann.

Signed-off-by: Alan Stern <stern-nwvwT67g6+6dFdvTe/***@public.gmane.org>
CC: David Brownell <david-b-yBeKhBN/***@public.gmane.org>

---

Index: usb-2.6/drivers/usb/host/ehci-dbg.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/ehci-dbg.c
+++ usb-2.6/drivers/usb/host/ehci-dbg.c
@@ -763,9 +763,7 @@ show_registers (struct class_device *cla
}

if (ehci->reclaim) {
- temp = scnprintf (next, size, "reclaim qh %p%s\n",
- ehci->reclaim,
- ehci->reclaim_ready ? " ready" : "");
+ temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim);
size -= temp;
next += temp;
}
Index: usb-2.6/drivers/usb/host/ehci-hcd.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/ehci-hcd.c
+++ usb-2.6/drivers/usb/host/ehci-hcd.c
@@ -109,7 +109,7 @@ static const char hcd_name [] = "ehci_hc
#define EHCI_TUNE_MULT_TT 1
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */

-#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
+#define EHCI_IAA_MSECS 10 /* arbitrary */
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
@@ -266,6 +266,7 @@ static void ehci_quiesce (struct ehci_hc

/*-------------------------------------------------------------------------*/

+static void end_unlink_async(struct ehci_hcd *ehci);
static void ehci_work(struct ehci_hcd *ehci);

#include "ehci-hub.c"
@@ -275,25 +276,41 @@ static void ehci_work(struct ehci_hcd *e

/*-------------------------------------------------------------------------*/

-static void ehci_watchdog (unsigned long param)
+static void ehci_iaa_watchdog(unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
unsigned long flags;
+ u32 status, cmd;

spin_lock_irqsave (&ehci->lock, flags);
+ WARN_ON(!ehci->reclaim);

- /* lost IAA irqs wedge things badly; seen with a vt8235 */
+ status = ehci_readl(ehci, &ehci->regs->status);
+ cmd = ehci_readl(ehci, &ehci->regs->command);
+ ehci_info(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
+
+ /* lost IAA irqs wedge things badly; seen first with a vt8235 */
if (ehci->reclaim) {
- u32 status = ehci_readl(ehci, &ehci->regs->status);
if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
ehci_writel(ehci, STS_IAA, &ehci->regs->status);
- ehci->reclaim_ready = 1;
}
+ ehci_writel(ehci, cmd & ~CMD_IAAD, &ehci->regs->command);
+ end_unlink_async(ehci);
}

- /* stop async processing after it's idled a bit */
+ spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+static void ehci_watchdog(unsigned long param)
+{
+ struct ehci_hcd *ehci = (struct ehci_hcd *) param;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ehci->lock, flags);
+
+ /* stop async processing after it's idled a bit */
if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
start_unlink_async (ehci, ehci->async);

@@ -363,8 +380,6 @@ static void ehci_port_power (struct ehci
static void ehci_work (struct ehci_hcd *ehci)
{
timer_action_done (ehci, TIMER_IO_WATCHDOG);
- if (ehci->reclaim_ready)
- end_unlink_async (ehci);

/* another CPU may drop ehci->lock during a schedule scan while
* it reports urb completions. this flag guards against bogus
@@ -399,6 +414,7 @@ static void ehci_stop (struct usb_hcd *h

/* no more interrupts ... */
del_timer_sync (&ehci->watchdog);
+ del_timer_sync(&ehci->iaa_watchdog);

spin_lock_irq(&ehci->lock);
if (HC_IS_RUNNING (hcd->state))
@@ -447,6 +463,10 @@ static int ehci_init(struct usb_hcd *hcd
ehci->watchdog.function = ehci_watchdog;
ehci->watchdog.data = (unsigned long) ehci;

+ init_timer(&ehci->iaa_watchdog);
+ ehci->iaa_watchdog.function = ehci_iaa_watchdog;
+ ehci->iaa_watchdog.data = (unsigned long) ehci;
+
/*
* hw default: 1K periodic list heads, one per frame.
* periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -463,7 +483,6 @@ static int ehci_init(struct usb_hcd *hcd
ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);

ehci->reclaim = NULL;
- ehci->reclaim_ready = 0;
ehci->next_uframe = -1;

/*
@@ -651,8 +670,7 @@ static irqreturn_t ehci_irq (struct usb_
/* complete the unlinking of some qh [4.15.2.3] */
if (status & STS_IAA) {
COUNT (ehci->stats.reclaim);
- ehci->reclaim_ready = 1;
- bh = 1;
+ end_unlink_async(ehci);
}

/* remote wakeup [4.3.1] */
@@ -758,10 +776,16 @@ static int ehci_urb_enqueue (

static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- /* if we need to use IAA and it's busy, defer */
- if (qh->qh_state == QH_STATE_LINKED
- && ehci->reclaim
- && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
+ /* failfast */
+ if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))
+ end_unlink_async(ehci);
+
+ /* if it's not linked then there's nothing to do */
+ if (qh->qh_state != QH_STATE_LINKED)
+ ;
+
+ /* defer till later if busy */
+ else if (ehci->reclaim) {
struct ehci_qh *last;

for (last = ehci->reclaim;
@@ -771,12 +795,8 @@ static void unlink_async (struct ehci_hc
qh->qh_state = QH_STATE_UNLINK_WAIT;
last->reclaim = qh;

- /* bypass IAA if the hc can't care */
- } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
- end_unlink_async (ehci);
-
- /* something else might have unlinked the qh by now */
- if (qh->qh_state == QH_STATE_LINKED)
+ /* start IAA cycle */
+ } else
start_unlink_async (ehci, qh);
}

@@ -803,7 +823,19 @@ static int ehci_urb_dequeue(struct usb_h
qh = (struct ehci_qh *) urb->hcpriv;
if (!qh)
break;
- unlink_async (ehci, qh);
+ switch (qh->qh_state) {
+ case QH_STATE_LINKED:
+ case QH_STATE_COMPLETING:
+ unlink_async(ehci, qh);
+ break;
+ case QH_STATE_UNLINK:
+ case QH_STATE_UNLINK_WAIT:
+ /* already started */
+ break;
+ case QH_STATE_IDLE:
+ WARN_ON(1);
+ break;
+ }
break;

case PIPE_INTERRUPT:
@@ -895,6 +927,7 @@ rescan:
unlink_async (ehci, qh);
/* FALL THROUGH */
case QH_STATE_UNLINK: /* wait for hw to finish? */
+ case QH_STATE_UNLINK_WAIT:
idle_timeout:
spin_unlock_irqrestore (&ehci->lock, flags);
schedule_timeout_uninterruptible(1);
Index: usb-2.6/drivers/usb/host/ehci-hub.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/ehci-hub.c
+++ usb-2.6/drivers/usb/host/ehci-hub.c
@@ -134,7 +134,7 @@ static int ehci_bus_suspend (struct usb_
}
ehci->command = ehci_readl(ehci, &ehci->regs->command);
if (ehci->reclaim)
- ehci->reclaim_ready = 1;
+ end_unlink_async(ehci);
ehci_work(ehci);

/* Unlike other USB host controller types, EHCI doesn't have
Index: usb-2.6/drivers/usb/host/ehci-pci.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/ehci-pci.c
+++ usb-2.6/drivers/usb/host/ehci-pci.c
@@ -305,7 +305,7 @@ static int ehci_pci_resume(struct usb_hc
/* emptying the schedule aborts any urbs */
spin_lock_irq(&ehci->lock);
if (ehci->reclaim)
- ehci->reclaim_ready = 1;
+ end_unlink_async(ehci);
ehci_work(ehci);
spin_unlock_irq(&ehci->lock);

Index: usb-2.6/drivers/usb/host/ehci-q.c
===================================================================
--- usb-2.6.orig/drivers/usb/host/ehci-q.c
+++ usb-2.6/drivers/usb/host/ehci-q.c
@@ -973,7 +973,7 @@ static void end_unlink_async (struct ehc
struct ehci_qh *qh = ehci->reclaim;
struct ehci_qh *next;

- timer_action_done (ehci, TIMER_IAA_WATCHDOG);
+ iaa_watchdog_done(ehci);

// qh->hw_next = cpu_to_hc32(qh->qh_dma);
qh->qh_state = QH_STATE_IDLE;
@@ -983,7 +983,6 @@ static void end_unlink_async (struct ehc
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim;
ehci->reclaim = next;
- ehci->reclaim_ready = 0;
qh->reclaim = NULL;

qh_completions (ehci, qh);
@@ -1059,11 +1058,10 @@ static void start_unlink_async (struct e
return;
}

- ehci->reclaim_ready = 0;
cmd |= CMD_IAAD;
ehci_writel(ehci, cmd, &ehci->regs->command);
(void)ehci_readl(ehci, &ehci->regs->command);
- timer_action (ehci, TIMER_IAA_WATCHDOG);
+ iaa_watchdog_start(ehci);
}

/*-------------------------------------------------------------------------*/
Index: usb-2.6/drivers/usb/host/ehci.h
===================================================================
--- usb-2.6.orig/drivers/usb/host/ehci.h
+++ usb-2.6/drivers/usb/host/ehci.h
@@ -74,7 +74,6 @@ struct ehci_hcd { /* one per controlle
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *reclaim;
- unsigned reclaim_ready : 1;
unsigned scanning : 1;

/* periodic schedule support */
@@ -105,6 +104,7 @@ struct ehci_hcd { /* one per controlle
struct dma_pool *itd_pool; /* itd per iso urb */
struct dma_pool *sitd_pool; /* sitd per split iso urb */

+ struct timer_list iaa_watchdog;
struct timer_list watchdog;
unsigned long actions;
unsigned stamp;
@@ -140,9 +140,21 @@ static inline struct usb_hcd *ehci_to_hc
}


+static inline void
+iaa_watchdog_start(struct ehci_hcd *ehci)
+{
+ WARN_ON(timer_pending(&ehci->iaa_watchdog));
+ mod_timer(&ehci->iaa_watchdog,
+ jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
+}
+
+static inline void iaa_watchdog_done(struct ehci_hcd *ehci)
+{
+ del_timer(&ehci->iaa_watchdog);
+}
+
enum ehci_timer_action {
TIMER_IO_WATCHDOG,
- TIMER_IAA_WATCHDOG,
TIMER_ASYNC_SHRINK,
TIMER_ASYNC_OFF,
};
@@ -160,9 +172,6 @@ timer_action (struct ehci_hcd *ehci, enu
unsigned long t;

switch (action) {
- case TIMER_IAA_WATCHDOG:
- t = EHCI_IAA_JIFFIES;
- break;
case TIMER_IO_WATCHDOG:
t = EHCI_IO_JIFFIES;
break;
@@ -179,8 +188,7 @@ timer_action (struct ehci_hcd *ehci, enu
// async queue SHRINK often precedes IAA. while it's ready
// to go OFF neither can matter, and afterwards the IO
// watchdog stops unless there's still periodic traffic.
- if (action != TIMER_IAA_WATCHDOG
- && t > ehci->watchdog.expires
+ if (time_before_eq(t, ehci->watchdog.expires)
&& timer_pending (&ehci->watchdog))
return;
mod_timer (&ehci->watchdog, t);

-
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
g***@suse.de
2007-12-20 23:37:24 UTC
Permalink
This is a note to let you know that I've just added the patch titled

Subject: USB: EHCI: add separate IAA watchdog timer

to my gregkh-2.6 tree. Its filename is

usb-ehci-add-separate-iaa-watchdog-timer.patch

This tree can be found at
http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/
From: Alan Stern <***@rowland.harvard.edu>
Date: Tue, 11 Dec 2007 16:05:30 -0500 (EST)
Subject: USB: EHCI: add separate IAA watchdog timer
To: Greg KH <***@kroah.com>
Cc: David Brownell <david-***@pacbell.net>, USB development list <linux-usb-***@lists.sourceforge.net>, USB list <linux-***@vger.kernel.org>
Message-ID: <Pine.LNX.4.44L0.0712111602340.2805-***@iolanthe.rowland.org>


This patch (as1028) was mostly written by David Brownell; I made only
a few changes (extra log info and a small bug fix -- which might
account for why David's version had to be reverted). It adds a new
watchdog timer to the ehci-hcd driver to be used exclusively for
detecting lost or missing IAA notifications.

Previously a shared timer had been used, which may have led to some
problems as reported by Christian Hoffmann.

Signed-off-by: Alan Stern <***@rowland.harvard.edu>
Cc: David Brownell <david-***@pacbell.net>
Signed-off-by: Greg Kroah-Hartman <***@suse.de>

---
drivers/usb/host/ehci-dbg.c | 4 --
drivers/usb/host/ehci-hcd.c | 77 +++++++++++++++++++++++++++++++-------------
drivers/usb/host/ehci-hub.c | 2 -
drivers/usb/host/ehci-pci.c | 2 -
drivers/usb/host/ehci-q.c | 6 +--
drivers/usb/host/ehci.h | 22 ++++++++----
6 files changed, 75 insertions(+), 38 deletions(-)

--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -786,9 +786,7 @@ static ssize_t fill_registers_buffer(str
}

if (ehci->reclaim) {
- temp = scnprintf (next, size, "reclaim qh %p%s\n",
- ehci->reclaim,
- ehci->reclaim_ready ? " ready" : "");
+ temp = scnprintf(next, size, "reclaim qh %p\n", ehci->reclaim);
size -= temp;
next += temp;
}
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -110,7 +110,7 @@ static const char hcd_name [] = "ehci_hc
#define EHCI_TUNE_MULT_TT 1
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */

-#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
+#define EHCI_IAA_MSECS 10 /* arbitrary */
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
@@ -267,6 +267,7 @@ static void ehci_quiesce (struct ehci_hc

/*-------------------------------------------------------------------------*/

+static void end_unlink_async(struct ehci_hcd *ehci);
static void ehci_work(struct ehci_hcd *ehci);

#include "ehci-hub.c"
@@ -276,25 +277,41 @@ static void ehci_work(struct ehci_hcd *e

/*-------------------------------------------------------------------------*/

-static void ehci_watchdog (unsigned long param)
+static void ehci_iaa_watchdog(unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
unsigned long flags;
+ u32 status, cmd;

spin_lock_irqsave (&ehci->lock, flags);
+ WARN_ON(!ehci->reclaim);

- /* lost IAA irqs wedge things badly; seen with a vt8235 */
+ status = ehci_readl(ehci, &ehci->regs->status);
+ cmd = ehci_readl(ehci, &ehci->regs->command);
+ ehci_info(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd);
+
+ /* lost IAA irqs wedge things badly; seen first with a vt8235 */
if (ehci->reclaim) {
- u32 status = ehci_readl(ehci, &ehci->regs->status);
if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
ehci_writel(ehci, STS_IAA, &ehci->regs->status);
- ehci->reclaim_ready = 1;
}
+ ehci_writel(ehci, cmd & ~CMD_IAAD, &ehci->regs->command);
+ end_unlink_async(ehci);
}

- /* stop async processing after it's idled a bit */
+ spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+static void ehci_watchdog(unsigned long param)
+{
+ struct ehci_hcd *ehci = (struct ehci_hcd *) param;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ehci->lock, flags);
+
+ /* stop async processing after it's idled a bit */
if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
start_unlink_async (ehci, ehci->async);

@@ -364,8 +381,6 @@ static void ehci_port_power (struct ehci
static void ehci_work (struct ehci_hcd *ehci)
{
timer_action_done (ehci, TIMER_IO_WATCHDOG);
- if (ehci->reclaim_ready)
- end_unlink_async (ehci);

/* another CPU may drop ehci->lock during a schedule scan while
* it reports urb completions. this flag guards against bogus
@@ -400,6 +415,7 @@ static void ehci_stop (struct usb_hcd *h

/* no more interrupts ... */
del_timer_sync (&ehci->watchdog);
+ del_timer_sync(&ehci->iaa_watchdog);

spin_lock_irq(&ehci->lock);
if (HC_IS_RUNNING (hcd->state))
@@ -448,6 +464,10 @@ static int ehci_init(struct usb_hcd *hcd
ehci->watchdog.function = ehci_watchdog;
ehci->watchdog.data = (unsigned long) ehci;

+ init_timer(&ehci->iaa_watchdog);
+ ehci->iaa_watchdog.function = ehci_iaa_watchdog;
+ ehci->iaa_watchdog.data = (unsigned long) ehci;
+
/*
* hw default: 1K periodic list heads, one per frame.
* periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -464,7 +484,6 @@ static int ehci_init(struct usb_hcd *hcd
ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);

ehci->reclaim = NULL;
- ehci->reclaim_ready = 0;
ehci->next_uframe = -1;

/*
@@ -655,8 +674,7 @@ static irqreturn_t ehci_irq (struct usb_
/* complete the unlinking of some qh [4.15.2.3] */
if (status & STS_IAA) {
COUNT (ehci->stats.reclaim);
- ehci->reclaim_ready = 1;
- bh = 1;
+ end_unlink_async(ehci);
}

/* remote wakeup [4.3.1] */
@@ -762,10 +780,16 @@ static int ehci_urb_enqueue (

static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- /* if we need to use IAA and it's busy, defer */
- if (qh->qh_state == QH_STATE_LINKED
- && ehci->reclaim
- && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
+ /* failfast */
+ if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))
+ end_unlink_async(ehci);
+
+ /* if it's not linked then there's nothing to do */
+ if (qh->qh_state != QH_STATE_LINKED)
+ ;
+
+ /* defer till later if busy */
+ else if (ehci->reclaim) {
struct ehci_qh *last;

for (last = ehci->reclaim;
@@ -775,12 +799,8 @@ static void unlink_async (struct ehci_hc
qh->qh_state = QH_STATE_UNLINK_WAIT;
last->reclaim = qh;

- /* bypass IAA if the hc can't care */
- } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
- end_unlink_async (ehci);
-
- /* something else might have unlinked the qh by now */
- if (qh->qh_state == QH_STATE_LINKED)
+ /* start IAA cycle */
+ } else
start_unlink_async (ehci, qh);
}

@@ -807,7 +827,19 @@ static int ehci_urb_dequeue(struct usb_h
qh = (struct ehci_qh *) urb->hcpriv;
if (!qh)
break;
- unlink_async (ehci, qh);
+ switch (qh->qh_state) {
+ case QH_STATE_LINKED:
+ case QH_STATE_COMPLETING:
+ unlink_async(ehci, qh);
+ break;
+ case QH_STATE_UNLINK:
+ case QH_STATE_UNLINK_WAIT:
+ /* already started */
+ break;
+ case QH_STATE_IDLE:
+ WARN_ON(1);
+ break;
+ }
break;

case PIPE_INTERRUPT:
@@ -899,6 +931,7 @@ rescan:
unlink_async (ehci, qh);
/* FALL THROUGH */
case QH_STATE_UNLINK: /* wait for hw to finish? */
+ case QH_STATE_UNLINK_WAIT:
idle_timeout:
spin_unlock_irqrestore (&ehci->lock, flags);
schedule_timeout_uninterruptible(1);
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -134,7 +134,7 @@ static int ehci_bus_suspend (struct usb_
}
ehci->command = ehci_readl(ehci, &ehci->regs->command);
if (ehci->reclaim)
- ehci->reclaim_ready = 1;
+ end_unlink_async(ehci);
ehci_work(ehci);

/* Unlike other USB host controller types, EHCI doesn't have
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -305,7 +305,7 @@ static int ehci_pci_resume(struct usb_hc
/* emptying the schedule aborts any urbs */
spin_lock_irq(&ehci->lock);
if (ehci->reclaim)
- ehci->reclaim_ready = 1;
+ end_unlink_async(ehci);
ehci_work(ehci);
spin_unlock_irq(&ehci->lock);

--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -973,7 +973,7 @@ static void end_unlink_async (struct ehc
struct ehci_qh *qh = ehci->reclaim;
struct ehci_qh *next;

- timer_action_done (ehci, TIMER_IAA_WATCHDOG);
+ iaa_watchdog_done(ehci);

// qh->hw_next = cpu_to_hc32(qh->qh_dma);
qh->qh_state = QH_STATE_IDLE;
@@ -983,7 +983,6 @@ static void end_unlink_async (struct ehc
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim;
ehci->reclaim = next;
- ehci->reclaim_ready = 0;
qh->reclaim = NULL;

qh_completions (ehci, qh);
@@ -1059,11 +1058,10 @@ static void start_unlink_async (struct e
return;
}

- ehci->reclaim_ready = 0;
cmd |= CMD_IAAD;
ehci_writel(ehci, cmd, &ehci->regs->command);
(void)ehci_readl(ehci, &ehci->regs->command);
- timer_action (ehci, TIMER_IAA_WATCHDOG);
+ iaa_watchdog_start(ehci);
}

/*-------------------------------------------------------------------------*/
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -74,7 +74,6 @@ struct ehci_hcd { /* one per controlle
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *reclaim;
- unsigned reclaim_ready : 1;
unsigned scanning : 1;

/* periodic schedule support */
@@ -105,6 +104,7 @@ struct ehci_hcd { /* one per controlle
struct dma_pool *itd_pool; /* itd per iso urb */
struct dma_pool *sitd_pool; /* sitd per split iso urb */

+ struct timer_list iaa_watchdog;
struct timer_list watchdog;
unsigned long actions;
unsigned stamp;
@@ -148,9 +148,21 @@ static inline struct usb_hcd *ehci_to_hc
}


+static inline void
+iaa_watchdog_start(struct ehci_hcd *ehci)
+{
+ WARN_ON(timer_pending(&ehci->iaa_watchdog));
+ mod_timer(&ehci->iaa_watchdog,
+ jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
+}
+
+static inline void iaa_watchdog_done(struct ehci_hcd *ehci)
+{
+ del_timer(&ehci->iaa_watchdog);
+}
+
enum ehci_timer_action {
TIMER_IO_WATCHDOG,
- TIMER_IAA_WATCHDOG,
TIMER_ASYNC_SHRINK,
TIMER_ASYNC_OFF,
};
@@ -168,9 +180,6 @@ timer_action (struct ehci_hcd *ehci, enu
unsigned long t;

switch (action) {
- case TIMER_IAA_WATCHDOG:
- t = EHCI_IAA_JIFFIES;
- break;
case TIMER_IO_WATCHDOG:
t = EHCI_IO_JIFFIES;
break;
@@ -187,8 +196,7 @@ timer_action (struct ehci_hcd *ehci, enu
// async queue SHRINK often precedes IAA. while it's ready
// to go OFF neither can matter, and afterwards the IO
// watchdog stops unless there's still periodic traffic.
- if (action != TIMER_IAA_WATCHDOG
- && t > ehci->watchdog.expires
+ if (time_before_eq(t, ehci->watchdog.expires)
&& timer_pending (&ehci->watchdog))
return;
mod_timer (&ehci->watchdog, t);


Patches currently in gregkh-2.6 which might be from ***@rowland.harvard.edu are

driver/pm-acquire-device-locks-prior-to-suspending.patch
driver/kobject-drop-child-parent-ref-at-unregistration.patch
driver/driver-core-fix-race-in-__device_release_driver.patch
driver/driver-core-fix-class-glue-dir-cleanup-logic.patch
usb/usb-add-usbfs-stubs-for-suspend-and-resume.patch
usb/usb-dummy_hcd-change-the-default-power-budget.patch
usb/usb-usb-storage-new-lockable-subclass-0x07.patch
usb/usb-ehci-add-separate-iaa-watchdog-timer.patch
usb/usb-usb-mon-mon_bin.c-cleanups.patch
usb/usb-autosuspend-for-cdc-acm.patch
usb/usb-repair-usbdevfs_connect-ioctl.patch
usb/usb-don-t-change-hc-power-state-for-a-freeze.patch
usb/usb-dummy_hcd-don-t-register-drivers-on-the-platform-bus.patch
usb/usb-force-handover-port-to-companion-when-hub_port_connect_change-fails.patch
usb/usb-make-ksuspend_usbd-thread-non-freezable.patch
usb/usb-updates-to-usb_reset_composite_device.patch

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
linux-usb-***@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Loading...