Merge branch 'master' into gfs2
[pandora-kernel.git] / drivers / usb / host / ehci-q.c
index 9b13bf2..7fc25b6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2001-2004 by David Brownell
- * 
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * Free Software Foundation; either version 2 of the License, or (at your
@@ -31,7 +31,7 @@
  * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
  * interrupts) needs careful scheduling.  Performance improvements can be
  * an ongoing challenge.  That's in "ehci-sched.c".
- * 
+ *
  * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
  * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
  * (b) special fields in qh entries or (c) split iso entries.  TTs will
@@ -199,7 +199,7 @@ static void qtd_copy_status (
                                && ((token & QTD_STS_MMF) != 0
                                        || QTD_CERR(token) == 0)
                                && (!ehci_is_TDI(ehci)
-                                       || urb->dev->tt->hub !=
+                                       || urb->dev->tt->hub !=
                                           ehci_to_hcd(ehci)->self.root_hub)) {
 #ifdef DEBUG
                        struct usb_device *tt = urb->dev->tt->hub;
@@ -364,7 +364,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
                         */
                        if (likely (urb->status == -EINPROGRESS))
                                continue;
-                       
+
                        /* issue status after short control reads */
                        if (unlikely (do_status != 0)
                                        && QTD_PID (token) == 0 /* OUT */) {
@@ -388,7 +388,7 @@ halt:
                                wmb ();
                        }
                }
+
                /* remove it from the queue */
                spin_lock (&urb->lock);
                qtd_copy_status (ehci, urb, qtd->length, token);
@@ -518,7 +518,7 @@ qh_urb_transaction (
                /* for zero length DATA stages, STATUS is always IN */
                if (len == 0)
                        token |= (1 /* "in" */ << 8);
-       } 
+       }
 
        /*
         * data transfer stage:  buffer setup
@@ -702,7 +702,7 @@ qh_make (
        }
 
        /* support for tt scheduling, and access to toggles */
-       qh->dev = usb_get_dev (urb->dev);
+       qh->dev = urb->dev;
 
        /* using TT? */
        switch (urb->dev->speed) {
@@ -721,7 +721,14 @@ qh_make (
                info1 |= maxp << 16;
 
                info2 |= (EHCI_TUNE_MULT_TT << 30);
-               info2 |= urb->dev->ttport << 23;
+
+               /* Some Freescale processors have an erratum in which the
+                * port number in the queue head was 0..N-1 instead of 1..N.
+                */
+               if (ehci_has_fsl_portno_bug(ehci))
+                       info2 |= (urb->dev->ttport-1) << 23;
+               else
+                       info2 |= urb->dev->ttport << 23;
 
                /* set the address of the TT; for TDI's integrated
                 * root hub tt, leave it zeroed.
@@ -752,7 +759,7 @@ qh_make (
                }
                break;
        default:
-               dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+               dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
 done:
                qh_put (qh);
                return NULL;
@@ -960,17 +967,16 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
        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_le32 (qh->qh_dma);
        qh->qh_state = QH_STATE_IDLE;
        qh->qh_next.qh = NULL;
-       qh_put (qh);                    // refcount from reclaim 
+       qh_put (qh);                    // refcount from reclaim
 
        /* 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, regs);
@@ -1015,14 +1021,16 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        /* stop async schedule right now? */
        if (unlikely (qh == ehci->async)) {
                /* can't get here without STS_ASS set */
-               if (ehci_to_hcd(ehci)->state != HC_STATE_HALT) {
+               if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
+                               && !ehci->reclaim) {
+                       /* ... and CMD_IAAD clear */
                        writel (cmd & ~CMD_ASE, &ehci->regs->command);
                        wmb ();
                        // handshake later, if we need to
+                       timer_action_done (ehci, TIMER_ASYNC_OFF);
                }
-               timer_action_done (ehci, TIMER_ASYNC_OFF);
                return;
-       } 
+       }
 
        qh->qh_state = QH_STATE_UNLINK;
        ehci->reclaim = qh = qh_get (qh);
@@ -1037,17 +1045,16 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
        if (unlikely (ehci_to_hcd(ehci)->state == HC_STATE_HALT)) {
                /* if (unlikely (qh->reclaim != 0))
-                *      this will recurse, probably not much
+                *      this will recurse, probably not much
                 */
                end_unlink_async (ehci, NULL);
                return;
        }
 
-       ehci->reclaim_ready = 0;
        cmd |= CMD_IAAD;
        writel (cmd, &ehci->regs->command);
        (void) readl (&ehci->regs->command);
-       timer_action (ehci, TIMER_IAA_WATCHDOG);
+       iaa_watchdog_start (ehci);
 }
 
 /*-------------------------------------------------------------------------*/