Merge to kernel-2.6.20-1.2949.fc6.vs2.2.0.1
[linux-2.6.git] / drivers / usb / host / ehci-pci.c
index cadffac..4bc7970 100644 (file)
@@ -238,6 +238,12 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
        writel (0, &ehci->regs->intr_enable);
        (void)readl(&ehci->regs->intr_enable);
 
+       /* make sure snapshot being resumed re-enumerates everything */
+       if (message.event == PM_EVENT_PRETHAW) {
+               ehci_halt(ehci);
+               ehci_reset(ehci);
+       }
+
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
  bail:
        spin_unlock_irqrestore (&ehci->lock, flags);
@@ -251,9 +257,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
 static int ehci_pci_resume(struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
-       unsigned                port;
        struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
-       int                     retval = -EINVAL;
 
        // maybe restore FLADJ
 
@@ -263,27 +267,19 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
        /* Mark hardware accessible again as we are out of D3 state by now */
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
-       /* If CF is clear, we lost PCI Vaux power and need to restart.  */
-       if (readl(&ehci->regs->configured_flag) != FLAG_CF)
-               goto restart;
-
-       /* If any port is suspended (or owned by the companion),
-        * we know we can/must resume the HC (and mustn't reset it).
-        * We just defer that to the root hub code.
+       /* If CF is still set, we maintained PCI Vaux power.
+        * Just undo the effect of ehci_pci_suspend().
         */
-       for (port = HCS_N_PORTS(ehci->hcs_params); port > 0; ) {
-               u32     status;
-               port--;
-               status = readl(&ehci->regs->port_status [port]);
-               if (!(status & PORT_POWER))
-                       continue;
-               if (status & (PORT_SUSPEND | PORT_RESUME | PORT_OWNER)) {
-                       usb_hcd_resume_root_hub(hcd);
-                       return 0;
-               }
+       if (readl(&ehci->regs->configured_flag) == FLAG_CF) {
+               int     mask = INTR_MASK;
+
+               if (!device_may_wakeup(&hcd->self.root_hub->dev))
+                       mask &= ~STS_PCD;
+               writel(mask, &ehci->regs->intr_enable);
+               readl(&ehci->regs->intr_enable);
+               return 0;
        }
 
-restart:
        ehci_dbg(ehci, "lost power, restarting\n");
        usb_root_hub_lost_power(hcd->self.root_hub);
 
@@ -298,16 +294,18 @@ restart:
        spin_lock_irq(&ehci->lock);
        if (ehci->reclaim)
                ehci->reclaim_ready = 1;
-       ehci_work(ehci, NULL);
+       ehci_work(ehci);
        spin_unlock_irq(&ehci->lock);
 
-       /* restart; khubd will disconnect devices */
-       retval = ehci_run(hcd);
-
        /* here we "know" root ports should always stay powered */
        ehci_port_power(ehci, 1);
 
-       return retval;
+       writel(ehci->command, &ehci->regs->command);
+       writel(FLAG_CF, &ehci->regs->configured_flag);
+       readl(&ehci->regs->command);    /* unblock posted writes */
+
+       hcd->state = HC_STATE_SUSPENDED;
+       return 0;
 }
 #endif
 
@@ -332,6 +330,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
        .resume =               ehci_pci_resume,
 #endif
        .stop =                 ehci_stop,
+       .shutdown =             ehci_shutdown,
 
        /*
         * managing i/o requests and associated device resources
@@ -378,4 +377,5 @@ static struct pci_driver ehci_pci_driver = {
        .suspend =      usb_hcd_pci_suspend,
        .resume =       usb_hcd_pci_resume,
 #endif
+       .shutdown =     usb_hcd_pci_shutdown,
 };