]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/host/ehci-q.c
Merge branch 'master' into upstream
[linux-2.6-omap-h63xx.git] / drivers / usb / host / ehci-q.c
index 940d38ca7d91785534bffe0f8da2f5e015c563a2..e469221e7ec392088fd1274e278175e29644f7a8 100644 (file)
@@ -477,7 +477,7 @@ qh_urb_transaction (
        struct ehci_hcd         *ehci,
        struct urb              *urb,
        struct list_head        *head,
-       int                     flags
+       gfp_t                   flags
 ) {
        struct ehci_qtd         *qtd, *qtd_prev;
        dma_addr_t              buf;
@@ -514,18 +514,18 @@ qh_urb_transaction (
                qtd->urb = urb;
                qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
                list_add_tail (&qtd->qtd_list, head);
+
+               /* for zero length DATA stages, STATUS is always IN */
+               if (len == 0)
+                       token |= (1 /* "in" */ << 8);
        } 
 
        /*
         * data transfer stage:  buffer setup
         */
-       if (likely (len > 0))
-               buf = urb->transfer_dma;
-       else
-               buf = 0;
+       buf = urb->transfer_dma;
 
-       /* for zero length DATA stages, STATUS is always IN */
-       if (!buf || is_input)
+       if (is_input)
                token |= (1 /* "in" */ << 8);
        /* else it's already initted to "out" pid (0 << 8) */
 
@@ -572,7 +572,7 @@ qh_urb_transaction (
         * control requests may need a terminating data "status" ack;
         * bulk ones may need a terminating short packet (zero length).
         */
-       if (likely (buf != 0)) {
+       if (likely (urb->transfer_buffer_length != 0)) {
                int     one_more = 0;
 
                if (usb_pipecontrol (urb->pipe)) {
@@ -629,7 +629,7 @@ static struct ehci_qh *
 qh_make (
        struct ehci_hcd         *ehci,
        struct urb              *urb,
-       int                     flags
+       gfp_t                   flags
 ) {
        struct ehci_qh          *qh = ehci_qh_alloc (ehci, flags);
        u32                     info1 = 0, info2 = 0;
@@ -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.
@@ -906,12 +913,13 @@ submit_async (
        struct usb_host_endpoint *ep,
        struct urb              *urb,
        struct list_head        *qtd_list,
-       unsigned                mem_flags
+       gfp_t                   mem_flags
 ) {
        struct ehci_qtd         *qtd;
        int                     epnum;
        unsigned long           flags;
        struct ehci_qh          *qh = NULL;
+       int                     rc = 0;
 
        qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
        epnum = ep->desc.bEndpointAddress;
@@ -926,21 +934,28 @@ submit_async (
 #endif
 
        spin_lock_irqsave (&ehci->lock, flags);
+       if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
+                              &ehci_to_hcd(ehci)->flags))) {
+               rc = -ESHUTDOWN;
+               goto done;
+       }
+
        qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+       if (unlikely(qh == NULL)) {
+               rc = -ENOMEM;
+               goto done;
+       }
 
        /* Control/bulk operations through TTs don't need scheduling,
         * the HC and TT handle it when the TT has a buffer ready.
         */
-       if (likely (qh != NULL)) {
-               if (likely (qh->qh_state == QH_STATE_IDLE))
-                       qh_link_async (ehci, qh_get (qh));
-       }
+       if (likely (qh->qh_state == QH_STATE_IDLE))
+               qh_link_async (ehci, qh_get (qh));
+ done:
        spin_unlock_irqrestore (&ehci->lock, flags);
-       if (unlikely (qh == NULL)) {
+       if (unlikely (qh == NULL))
                qtd_list_free (ehci, urb, qtd_list);
-               return -ENOMEM;
-       }
-       return 0;
+       return rc;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1007,12 +1022,14 @@ 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;
        }