USB: add missing delay during remote wakeup
[safe/jmp/linux-2.6] / drivers / usb / host / ehci-hcd.c
index c227ba4..1ec3857 100644 (file)
@@ -28,9 +28,9 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/timer.h>
+#include <linux/ktime.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>
-#include <linux/reboot.h>
 #include <linux/usb.h>
 #include <linux/moduleparam.h>
 #include <linux/dma-mapping.h>
@@ -210,7 +210,7 @@ static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
        if (error) {
                ehci_halt(ehci);
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
-               ehci_err(ehci, "force halt; handhake %p %08x %08x -> %d\n",
+               ehci_err(ehci, "force halt; handshake %p %08x %08x -> %d\n",
                        ptr, mask, done, error);
        }
 
@@ -241,6 +241,11 @@ static int ehci_reset (struct ehci_hcd *ehci)
        int     retval;
        u32     command = ehci_readl(ehci, &ehci->regs->command);
 
+       /* If the EHCI debug controller is active, special care must be
+        * taken before and after a host controller reset */
+       if (ehci->debug && !dbgp_reset_prep())
+               ehci->debug = NULL;
+
        command |= CMD_RESET;
        dbg_cmd (ehci, "reset", command);
        ehci_writel(ehci, command, &ehci->regs->command);
@@ -261,6 +266,9 @@ static int ehci_reset (struct ehci_hcd *ehci)
        if (ehci_is_TDI(ehci))
                tdi_reset (ehci);
 
+       if (ehci->debug)
+               dbgp_external_startup();
+
        return retval;
 }
 
@@ -541,7 +549,7 @@ static int ehci_init(struct usb_hcd *hcd)
        /* controllers may cache some of the periodic schedule ... */
        hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
        if (HCC_ISOC_CACHE(hcc_params))         // full frame cache
-               ehci->i_thresh = 8;
+               ehci->i_thresh = 2 + 8;
        else                                    // N microframes cached
                ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
 
@@ -597,6 +605,8 @@ static int ehci_init(struct usb_hcd *hcd)
        }
        ehci->command = temp;
 
+       /* Accept arbitrarily long scatter-gather lists */
+       hcd->self.sg_tablesize = ~0;
        return 0;
 }
 
@@ -669,6 +679,7 @@ static int ehci_run (struct usb_hcd *hcd)
        ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
        msleep(5);
        up_write(&ehci_cf_port_reset_rwsem);
+       ehci->last_periodic_enable = ktime_get_real();
 
        temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
        ehci_info (ehci,
@@ -776,9 +787,10 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 
                        /* start 20 msec resume signaling from this port,
                         * and make khubd collect PORT_STAT_C_SUSPEND to
-                        * stop that signaling.
+                        * stop that signaling.  Use 5 ms extra for safety,
+                        * like usb_port_resume() does.
                         */
-                       ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
+                       ehci->reset_done[i] = jiffies + msecs_to_jiffies(25);
                        ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
                        mod_timer(&hcd->rh_timer, ehci->reset_done[i]);
                }
@@ -864,12 +876,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim)
                end_unlink_async(ehci);
 
-       /* if it's not linked then there's nothing to do */
-       if (qh->qh_state != QH_STATE_LINKED)
-               ;
+       /* If the QH isn't linked then there's nothing we can do
+        * unless we were called during a giveback, in which case
+        * qh_completions() has to deal with it.
+        */
+       if (qh->qh_state != QH_STATE_LINKED) {
+               if (qh->qh_state == QH_STATE_COMPLETING)
+                       qh->needs_rescan = 1;
+               return;
+       }
 
        /* defer till later if busy */
-       else if (ehci->reclaim) {
+       if (ehci->reclaim) {
                struct ehci_qh          *last;
 
                for (last = ehci->reclaim;
@@ -929,8 +947,9 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                        break;
                switch (qh->qh_state) {
                case QH_STATE_LINKED:
+               case QH_STATE_COMPLETING:
                        intr_deschedule (ehci, qh);
-                       /* FALL THROUGH */
+                       break;
                case QH_STATE_IDLE:
                        qh_completions (ehci, qh);
                        break;
@@ -939,23 +958,6 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                                        qh, qh->qh_state);
                        goto done;
                }
-
-               /* reschedule QH iff another request is queued */
-               if (!list_empty (&qh->qtd_list)
-                               && HC_IS_RUNNING (hcd->state)) {
-                       rc = qh_schedule(ehci, qh);
-
-                       /* An error here likely indicates handshake failure
-                        * or no space left in the schedule.  Neither fault
-                        * should happen often ...
-                        *
-                        * FIXME kill the now-dysfunctional queued urbs
-                        */
-                       if (rc != 0)
-                               ehci_err(ehci,
-                                       "can't reschedule qh %p, err %d",
-                                       qh, rc);
-               }
                break;
 
        case PIPE_ISOCHRONOUS:
@@ -1002,6 +1004,7 @@ rescan:
                qh->qh_state = QH_STATE_IDLE;
        switch (qh->qh_state) {
        case QH_STATE_LINKED:
+       case QH_STATE_COMPLETING:
                for (tmp = ehci->async->qh_next.qh;
                                tmp && tmp != qh;
                                tmp = tmp->qh_next.qh)
@@ -1066,18 +1069,17 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
                usb_settoggle(qh->dev, epnum, is_out, 0);
                if (!list_empty(&qh->qtd_list)) {
                        WARN_ONCE(1, "clear_halt for a busy endpoint\n");
-               } else if (qh->qh_state == QH_STATE_LINKED) {
+               } else if (qh->qh_state == QH_STATE_LINKED ||
+                               qh->qh_state == QH_STATE_COMPLETING) {
 
                        /* The toggle value in the QH can't be updated
                         * while the QH is active.  Unlink it now;
                         * re-linking will call qh_refresh().
                         */
-                       if (eptype == USB_ENDPOINT_XFER_BULK) {
+                       if (eptype == USB_ENDPOINT_XFER_BULK)
                                unlink_async(ehci, qh);
-                       } else {
+                       else
                                intr_deschedule(ehci, qh);
-                               (void) qh_schedule(ehci, qh);
-                       }
                }
        }
        spin_unlock_irqrestore(&ehci->lock, flags);
@@ -1106,11 +1108,21 @@ MODULE_LICENSE ("GPL");
 #define        PLATFORM_DRIVER         ehci_fsl_driver
 #endif
 
+#ifdef CONFIG_USB_EHCI_MXC
+#include "ehci-mxc.c"
+#define PLATFORM_DRIVER                ehci_mxc_driver
+#endif
+
 #ifdef CONFIG_SOC_AU1200
 #include "ehci-au1xxx.c"
 #define        PLATFORM_DRIVER         ehci_hcd_au1xxx_driver
 #endif
 
+#ifdef CONFIG_ARCH_OMAP34XX
+#include "ehci-omap.c"
+#define        PLATFORM_DRIVER         ehci_hcd_omap_driver
+#endif
+
 #ifdef CONFIG_PPC_PS3
 #include "ehci-ps3.c"
 #define        PS3_SYSTEM_BUS_DRIVER   ps3_ehci_driver
@@ -1121,6 +1133,11 @@ MODULE_LICENSE ("GPL");
 #define OF_PLATFORM_DRIVER     ehci_hcd_ppc_of_driver
 #endif
 
+#ifdef CONFIG_XPS_USB_HCD_XILINX
+#include "ehci-xilinx-of.c"
+#define OF_PLATFORM_DRIVER     ehci_hcd_xilinx_of_driver
+#endif
+
 #ifdef CONFIG_PLAT_ORION
 #include "ehci-orion.c"
 #define        PLATFORM_DRIVER         ehci_orion_driver