Revert "Revert "EHCI: keep track of ports being resumed and indicate in hub_status_data""
Varun Wadekar [Fri, 25 May 2012 04:30:39 +0000 (09:30 +0530)]
This reverts commit 79972f9677dd651fdeaf7b343a905b20e731f31f.

drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/ehci.h

index 012b0e6..1beae0b 100644 (file)
@@ -353,6 +353,8 @@ static int ehci_reset (struct ehci_hcd *ehci)
        if (ehci->debug)
                dbgp_external_startup();
 
+       ehci->port_c_suspend = ehci->suspended_ports =
+                       ehci->resuming_ports = 0;
        return retval;
 }
 
@@ -950,6 +952,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
                         * like usb_port_resume() does.
                         */
                        ehci->reset_done[i] = jiffies + msecs_to_jiffies(25);
+                       set_bit(i, &ehci->resuming_ports);
                        ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
                        mod_timer(&hcd->rh_timer, ehci->reset_done[i]);
 #ifdef CONFIG_USB_EHCI_TEGRA
index aeef72c..37e6821 100644 (file)
@@ -222,15 +222,10 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
         * remote wakeup, we must fail the suspend.
         */
        if (hcd->self.root_hub->do_remote_wakeup) {
-               port = HCS_N_PORTS(ehci->hcs_params);
-               while (port--) {
-                       if (ehci->reset_done[port] != 0) {
-                               spin_unlock_irq(&ehci->lock);
-                               ehci_dbg(ehci, "suspend failed because "
-                                               "port %d is resuming\n",
-                                               port + 1);
-                               return -EBUSY;
-                       }
+               if (ehci->resuming_ports) {
+                       spin_unlock_irq(&ehci->lock);
+                       ehci_dbg(ehci, "suspend failed because a port is resuming\n");
+                       return -EBUSY;
                }
        }
 
@@ -553,16 +548,12 @@ static int
 ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
 {
        struct ehci_hcd *ehci = hcd_to_ehci (hcd);
-       u32             temp, status = 0;
+       u32             temp, status;
        u32             mask;
        int             ports, i, retval = 1;
        unsigned long   flags;
        u32             ppcd = 0;
 
-       /* if !USB_SUSPEND, root hub timers won't get shut down ... */
-       if (ehci->rh_state != EHCI_RH_RUNNING)
-               return 0;
-
        /* init status to no-changes */
        buf [0] = 0;
        ports = HCS_N_PORTS (ehci->hcs_params);
@@ -571,6 +562,11 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
                retval++;
        }
 
+       /* Inform the core about resumes-in-progress by returning
+        * a non-zero value even if there are no status changes.
+        */
+       status = ehci->resuming_ports;
+
        /* Some boards (mostly VIA?) report bogus overcurrent indications,
         * causing massive log spam unless we completely ignore them.  It
         * may be relevant that VIA VT8235 controllers, where PORT_POWER is
@@ -838,6 +834,7 @@ static int ehci_hub_control (
                                ehci_writel(ehci,
                                        temp & ~(PORT_RWC_BITS | PORT_RESUME),
                                        status_reg);
+                               clear_bit(wIndex, &ehci->resuming_ports);
                                retval = handshake(ehci, status_reg,
                                           PORT_RESUME, 0, 2000 /* 2msec */);
                                if (retval != 0) {
@@ -856,6 +853,7 @@ static int ehci_hub_control (
                                        ehci->reset_done[wIndex])) {
                        status |= USB_PORT_STAT_C_RESET << 16;
                        ehci->reset_done [wIndex] = 0;
+                       clear_bit(wIndex, &ehci->resuming_ports);
 
                        /* force reset to complete */
                        ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
@@ -876,8 +874,10 @@ static int ehci_hub_control (
                                        ehci_readl(ehci, status_reg));
                }
 
-               if (!(temp & (PORT_RESUME|PORT_RESET)))
+               if (!(temp & (PORT_RESUME|PORT_RESET))) {
                        ehci->reset_done[wIndex] = 0;
+                       clear_bit(wIndex, &ehci->resuming_ports);
+               }
 
                /* transfer dedicated ports to the companion hc */
                if ((temp & PORT_CONNECT) &&
@@ -912,6 +912,7 @@ static int ehci_hub_control (
                        status |= USB_PORT_STAT_SUSPEND;
                } else if (test_bit(wIndex, &ehci->suspended_ports)) {
                        clear_bit(wIndex, &ehci->suspended_ports);
+                       clear_bit(wIndex, &ehci->resuming_ports);
                        ehci->reset_done[wIndex] = 0;
                        if (temp & PORT_PE)
                                set_bit(wIndex, &ehci->port_c_suspend);
index 328d0fa..abd92cb 100644 (file)
@@ -421,6 +421,7 @@ static int tegra_ehci_hub_control(
                temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
                /* start resume signaling */
                ehci_writel(ehci, temp | PORT_RESUME, status_reg);
+               set_bit(wIndex-1, &ehci->resuming_ports);
 
                ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25);
                /* whoever resumes must GetPortStatus to complete it!! */
@@ -471,7 +472,7 @@ static int tegra_ehci_hub_control(
                                if (hsic && (wIndex == 0))
                                        tegra_usb_phy_bus_reset(tegra->phy);
                        }
-
+                       clear_bit(wIndex-1, &ehci->resuming_ports);
                        break;
                }
                case USB_PORT_FEAT_POWER:
index bf88874..345b0dc 100644 (file)
@@ -117,6 +117,8 @@ struct ehci_hcd {                   /* one per controller */
                        the change-suspend feature turned on */
        unsigned long           suspended_ports;        /* which ports are
                        suspended */
+       unsigned long           resuming_ports;         /* which ports have
+                       started to resume */
 
        /* per-HC memory pools (could be per-bus, but ...) */
        struct dma_pool         *qh_pool;       /* qh per active urb */