vserver 1.9.3
[linux-2.6.git] / drivers / usb / host / ehci-hcd.c
index 7a52853..e25adf5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 by David Brownell
+ * Copyright (c) 2000-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
@@ -69,6 +69,7 @@
  *
  * HISTORY:
  *
+ * 2004-05-10 Root hub and PCI suspend/resume support; remote wakeup. (db)
  * 2004-02-24 Replace pci_* with generic dma_* API calls (dsaxena@plexity.net)
  * 2003-12-29 Rewritten high speed iso transfer support (by Michal Sojka,
  *     <sojkam@centrum.cz>, updates by DB).
@@ -96,7 +97,7 @@
  * 2001-June   Works with usb-storage and NEC EHCI on 2.4
  */
 
-#define DRIVER_VERSION "2003-Dec-29"
+#define DRIVER_VERSION "2004-May-10"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
@@ -128,7 +129,7 @@ static int log2_irq_thresh = 0;             // 0 to 6
 module_param (log2_irq_thresh, int, S_IRUGO);
 MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
 
-#define        INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
+#define        INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
 
 /*-------------------------------------------------------------------------*/
 
@@ -154,7 +155,7 @@ MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
  * before driver shutdown. But it also seems to be caused by bugs in cardbus
  * bridge shutdown:  shutting down the bridge before the devices using it.
  */
-static int handshake (u32 *ptr, u32 mask, u32 done, int usec)
+static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec)
 {
        u32     result;
 
@@ -201,6 +202,7 @@ static int ehci_reset (struct ehci_hcd *ehci)
        dbg_cmd (ehci, "reset", command);
        writel (command, &ehci->regs->command);
        ehci->hcd.state = USB_STATE_HALT;
+       ehci->next_statechange = jiffies;
        return handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
 }
 
@@ -241,6 +243,8 @@ static void ehci_ready (struct ehci_hcd *ehci)
 
 /*-------------------------------------------------------------------------*/
 
+static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
+
 #include "ehci-hub.c"
 #include "ehci-mem.c"
 #include "ehci-q.c"
@@ -248,8 +252,6 @@ static void ehci_ready (struct ehci_hcd *ehci)
 
 /*-------------------------------------------------------------------------*/
 
-static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
-
 static void ehci_watchdog (unsigned long param)
 {
        struct ehci_hcd         *ehci = (struct ehci_hcd *) param;
@@ -287,22 +289,26 @@ static void ehci_watchdog (unsigned long param)
 static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
 {
        if (cap & (1 << 16)) {
-               int msec = 500;
+               int msec = 5000;
+               struct pci_dev *pdev = to_pci_dev(ehci->hcd.self.controller);
 
                /* request handoff to OS */
-               cap &= 1 << 24;
-               pci_write_config_dword (to_pci_dev(ehci->hcd.self.controller), where, cap);
+               cap |= 1 << 24;
+               pci_write_config_dword(pdev, where, cap);
 
                /* and wait a while for it to happen */
                do {
-                       wait_ms (10);
+                       msleep(10);
                        msec -= 10;
-                       pci_read_config_dword (to_pci_dev(ehci->hcd.self.controller), where, &cap);
+                       pci_read_config_dword(pdev, where, &cap);
                } while ((cap & (1 << 16)) && msec);
                if (cap & (1 << 16)) {
                        ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n",
                                where, cap);
-                       return 1;
+                       // some BIOS versions seem buggy...
+                       // return 1;
+                       ehci_warn (ehci, "continuing after BIOS bug...\n");
+                       return 0;
                } 
                ehci_dbg (ehci, "BIOS handoff succeeded\n");
        }
@@ -334,8 +340,8 @@ static int ehci_hc_reset (struct usb_hcd *hcd)
 
        spin_lock_init (&ehci->lock);
 
-       ehci->caps = (struct ehci_caps *) hcd->regs;
-       ehci->regs = (struct ehci_regs *) (hcd->regs + 
+       ehci->caps = hcd->regs;
+       ehci->regs = (hcd->regs + 
                                HC_LENGTH (readl (&ehci->caps->hc_capbase)));
        dbg_hcs_params (ehci, "reset");
        dbg_hcc_params (ehci, "reset");
@@ -412,7 +418,7 @@ static int ehci_start (struct usb_hcd *hcd)
        else                                    // N microframes cached
                ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params);
 
-       ehci->reclaim = 0;
+       ehci->reclaim = NULL;
        ehci->next_uframe = -1;
 
        /* controller state:  unknown --> reset */
@@ -422,18 +428,22 @@ static int ehci_start (struct usb_hcd *hcd)
                ehci_mem_cleanup (ehci);
                return retval;
        }
-       writel (INTR_MASK, &ehci->regs->intr_enable);
        writel (ehci->periodic_dma, &ehci->regs->frame_list);
 
 #ifdef CONFIG_PCI
        if (hcd->self.controller->bus == &pci_bus_type) {
                struct pci_dev          *pdev;
+               u16                     port_wake;
 
                pdev = to_pci_dev(hcd->self.controller);
 
                /* Serial Bus Release Number is at PCI 0x60 offset */
                pci_read_config_byte(pdev, 0x60, &sbrn);
 
+               /* port wake capability, reported by boot firmware */
+               pci_read_config_word(pdev, 0x62, &port_wake);
+               hcd->can_wakeup = (port_wake & 1) != 0;
+
                /* help hc dma work well with cachelines */
                pci_set_mwi (pdev);
 
@@ -455,7 +465,7 @@ static int ehci_start (struct usb_hcd *hcd)
         * its dummy is used in hw_alt_next of many tds, to prevent the qh
         * from automatically advancing to the next td after short reads.
         */
-       ehci->async->qh_next.qh = 0;
+       ehci->async->qh_next.qh = NULL;
        ehci->async->hw_next = QH_NEXT (ehci->async->qh_dma);
        ehci->async->hw_info1 = cpu_to_le32 (QH_HEAD);
        ehci->async->hw_token = cpu_to_le32 (QTD_STS_HALT);
@@ -513,7 +523,7 @@ static int ehci_start (struct usb_hcd *hcd)
 
        /* wire up the root hub */
        bus = hcd_to_bus (hcd);
-       bus->root_hub = udev = usb_alloc_dev (NULL, bus, 0);
+       udev = usb_alloc_dev (NULL, bus, 0);
        if (!udev) {
 done2:
                ehci_mem_cleanup (ehci);
@@ -523,7 +533,8 @@ done2:
        /*
         * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
         * are explicitly handed to companion controller(s), so no TT is
-        * involved with the root hub.
+        * involved with the root hub.  (Except where one is integrated,
+        * and there's no companion controller unless maybe for USB OTG.)
         */
        ehci->reboot_notifier.notifier_call = ehci_reboot;
        register_reboot_notifier (&ehci->reboot_notifier);
@@ -546,16 +557,17 @@ done2:
         * and device drivers may start it running.
         */
        udev->speed = USB_SPEED_HIGH;
-       if (hcd_register_root (hcd) != 0) {
+       if (hcd_register_root (udev, hcd) != 0) {
                if (hcd->state == USB_STATE_RUNNING)
                        ehci_ready (ehci);
                ehci_reset (ehci);
-               bus->root_hub = 0;
                usb_put_dev (udev); 
                retval = -ENODEV;
                goto done2;
        }
 
+       writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+
        create_debug_files (ehci);
 
        return 0;
@@ -566,6 +578,7 @@ done2:
 static void ehci_stop (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
+       u8                      rh_ports, port;
 
        ehci_dbg (ehci, "stop\n");
 
@@ -577,7 +590,16 @@ static void ehci_stop (struct usb_hcd *hcd)
                return;
        }
        del_timer_sync (&ehci->watchdog);
+
+       /* Turn off port power on all root hub ports. */
+       rh_ports = HCS_N_PORTS (ehci->hcs_params);
+       for (port = 1; port <= rh_ports; port++) {
+               ehci_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER,
+                       port, NULL, 0);
+       }
+
        ehci_reset (ehci);
+       writel (0, &ehci->regs->intr_enable);
 
        /* let companion controllers work when we aren't */
        writel (0, &ehci->regs->configured_flag);
@@ -615,41 +637,26 @@ static int ehci_get_frame (struct usb_hcd *hcd)
 
 /* suspend/resume, section 4.3 */
 
+/* These routines rely on PCI to handle powerdown and wakeup, and
+ * transceivers that don't need any software attention to set up
+ * the right sort of wakeup.  
+ */
+
 static int ehci_suspend (struct usb_hcd *hcd, u32 state)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
-       int                     ports;
-       int                     i;
-
-       ehci_dbg (ehci, "suspend to %d\n", state);
 
-       ports = HCS_N_PORTS (ehci->hcs_params);
+       while (time_before (jiffies, ehci->next_statechange))
+               msleep (100);
 
-       // FIXME:  This assumes what's probably a D3 level suspend...
-
-       // FIXME:  usb wakeup events on this bus should resume the machine.
-       // pci config register PORTWAKECAP controls which ports can do it;
-       // bios may have initted the register...
-
-       /* suspend each port, then stop the hc */
-       for (i = 0; i < ports; i++) {
-               int     temp = readl (&ehci->regs->port_status [i]);
-
-               if ((temp & PORT_PE) == 0
-                               || (temp & PORT_OWNER) != 0)
-                       continue;
-               ehci_dbg (ehci, "suspend port %d", i);
-               temp |= PORT_SUSPEND;
-               writel (temp, &ehci->regs->port_status [i]);
-       }
-
-       if (hcd->state == USB_STATE_RUNNING)
-               ehci_ready (ehci);
-       writel (readl (&ehci->regs->command) & ~CMD_RUN, &ehci->regs->command);
-
-// save pci FLADJ value
+#ifdef CONFIG_USB_SUSPEND
+       (void) usb_suspend_device (hcd->self.root_hub, state);
+#else
+       /* FIXME lock root hub */
+       (void) ehci_hub_suspend (hcd);
+#endif
 
-       /* who tells PCI to reduce power consumption? */
+       // save (PCI) FLADJ in case of Vaux power loss
 
        return 0;
 }
@@ -657,40 +664,22 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
 static int ehci_resume (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
-       int                     ports;
-       int                     i;
-
-       ehci_dbg (ehci, "resume\n");
-
-       ports = HCS_N_PORTS (ehci->hcs_params);
-
-       // FIXME:  if controller didn't retain state,
-       // return and let generic code clean it up
-       // test configured_flag ?
-
-       /* resume HC and each port */
-// restore pci FLADJ value
-       // khubd and drivers will set HC running, if needed;
-       hcd->state = USB_STATE_RUNNING;
-       // FIXME Philips/Intel/... etc don't really have a "READY"
-       // state ... turn on CMD_RUN too
-       for (i = 0; i < ports; i++) {
-               int     temp = readl (&ehci->regs->port_status [i]);
-
-               if ((temp & PORT_PE) == 0
-                               || (temp & PORT_SUSPEND) != 0)
-                       continue;
-               ehci_dbg (ehci, "resume port %d", i);
-               temp |= PORT_RESUME;
-               writel (temp, &ehci->regs->port_status [i]);
-               readl (&ehci->regs->command);   /* unblock posted writes */
-
-               wait_ms (20);
-               temp &= ~PORT_RESUME;
-               writel (temp, &ehci->regs->port_status [i]);
-       }
-       readl (&ehci->regs->command);   /* unblock posted writes */
-       return 0;
+       int                     retval;
+
+       // maybe restore (PCI) FLADJ
+
+       while (time_before (jiffies, ehci->next_statechange))
+               msleep (100);
+
+#ifdef CONFIG_USB_SUSPEND
+       retval = usb_resume_device (hcd->self.root_hub);
+#else
+       /* FIXME lock root hub */
+       retval = ehci_hub_resume (hcd);
+#endif
+       if (retval == 0)
+               hcd->self.controller->power.power_state = 0;
+       return retval;
 }
 
 #endif
@@ -706,9 +695,18 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
        timer_action_done (ehci, TIMER_IO_WATCHDOG);
        if (ehci->reclaim_ready)
                end_unlink_async (ehci, regs);
+
+       /* another CPU may drop ehci->lock during a schedule scan while
+        * it reports urb completions.  this flag guards against bogus
+        * attempts at re-entrant schedule scanning.
+        */
+       if (ehci->scanning)
+               return;
+       ehci->scanning = 1;
        scan_async (ehci, regs);
        if (ehci->next_uframe != -1)
                scan_periodic (ehci, regs);
+       ehci->scanning = 0;
 
        /* the IO watchdog guards against hardware or driver bugs that
         * misplace IRQs, and should let us run completely without IRQs.
@@ -730,12 +728,6 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
 
        status = readl (&ehci->regs->status);
 
-       /* shared irq */
-       if (status == 0) {
-               spin_unlock (&ehci->lock);
-               return IRQ_NONE;
-       }
-
        /* e.g. cardbus physical eject */
        if (status == ~(u32) 0) {
                ehci_dbg (ehci, "device removed\n");
@@ -743,8 +735,10 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
        }
 
        status &= INTR_MASK;
-       if (!status)                    /* irq sharing? */
-               goto done;
+       if (!status) {                  /* irq sharing? */
+               spin_unlock(&ehci->lock);
+               return IRQ_NONE;
+       }
 
        /* clear (just) interrupts */
        writel (status, &ehci->regs->status);
@@ -752,7 +746,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
        bh = 0;
 
 #ifdef EHCI_VERBOSE_DEBUG
-       /* unrequested/ignored: Port Change Detect, Frame List Rollover */
+       /* unrequested/ignored: Frame List Rollover */
        dbg_status (ehci, "irq", status);
 #endif
 
@@ -774,6 +768,34 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
                bh = 1;
        }
 
+       /* remote wakeup [4.3.1] */
+       if ((status & STS_PCD) && ehci->hcd.remote_wakeup) {
+               unsigned        i = HCS_N_PORTS (ehci->hcs_params);
+
+               /* resume root hub? */
+               status = readl (&ehci->regs->command);
+               if (!(status & CMD_RUN))
+                       writel (status | CMD_RUN, &ehci->regs->command);
+
+               while (i--) {
+                       status = readl (&ehci->regs->port_status [i]);
+                       if (status & PORT_OWNER)
+                               continue;
+                       if (!(status & PORT_RESUME)
+                                       || ehci->reset_done [i] != 0)
+                               continue;
+
+                       /* start 20 msec resume signaling from this port,
+                        * and make khubd collect PORT_STAT_C_SUSPEND to
+                        * stop that signaling.
+                        */
+                       ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
+                       mod_timer (&ehci->hcd.rh_timer,
+                                       ehci->reset_done [i] + 1);
+                       ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
+               }
+       }
+
        /* PCI errors [4.15.2.4] */
        if (unlikely ((status & STS_FATAL) != 0)) {
                ehci_err (ehci, "fatal error\n");
@@ -787,7 +809,6 @@ dead:
 
        if (bh)
                ehci_work (ehci, regs);
-done:
        spin_unlock (&ehci->lock);
        return IRQ_HANDLED;
 }
@@ -814,7 +835,6 @@ static int ehci_urb_enqueue (
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        struct list_head        qtd_list;
 
-       urb->transfer_flags &= ~EHCI_STATE_UNLINK;
        INIT_LIST_HEAD (&qtd_list);
 
        switch (usb_pipetype (urb->pipe)) {
@@ -914,7 +934,6 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 
                // wait till next completion, do it then.
                // completion irqs can wait up to 1024 msec,
-               urb->transfer_flags |= EHCI_STATE_UNLINK;
                break;
        }
        spin_unlock_irqrestore (&ehci->lock, flags);
@@ -965,7 +984,7 @@ idle_timeout:
                goto rescan;
        case QH_STATE_IDLE:             /* fully unlinked */
                if (list_empty (&qh->qtd_list)) {
-                       qh_put (ehci, qh);
+                       qh_put (qh);
                        break;
                }
                /* else FALL THROUGH */
@@ -978,7 +997,7 @@ idle_timeout:
                        list_empty (&qh->qtd_list) ? "" : "(has tds)");
                break;
        }
-       dev->ep [epnum] = 0;
+       dev->ep[epnum] = NULL;
 done:
        spin_unlock_irqrestore (&ehci->lock, flags);
        return;
@@ -1029,6 +1048,8 @@ static const struct hc_driver ehci_driver = {
         */
        .hub_status_data =      ehci_hub_status_data,
        .hub_control =          ehci_hub_control,
+       .hub_suspend =          ehci_hub_suspend,
+       .hub_resume =           ehci_hub_resume,
 };
 
 /*-------------------------------------------------------------------------*/