usb: host: tegra: Reduce busy polling duration
authorJay Cheng <jacheng@nvidia.com>
Mon, 22 Nov 2010 16:03:52 +0000 (11:03 -0500)
committerBenoit Goby <benoit@android.com>
Mon, 29 Nov 2010 20:29:39 +0000 (12:29 -0800)
Change-Id: I63e271409818e33b4c19bb99b00e556bc5a2a4b3
Signed-off-by: Jay Cheng <jacheng@nvidia.com>
drivers/usb/host/ehci-tegra.c

index 60db07950528a70e5ce682344d37669e46df4eb1..5cdad2531ba1473253d75b034836b50ec06a83fd 100644 (file)
@@ -91,35 +91,34 @@ static int tegra_ehci_hub_control(
 
        status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1];
 
+       spin_lock_irqsave(&ehci->lock, flags);
+
        /*
         * In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits
         * that are write on clear, by writing back the register read value, so
         * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits
         */
        if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) {
-               spin_lock_irqsave(&ehci->lock, flags);
                temp = ehci_readl(ehci, status_reg);
                ehci_writel(ehci, (temp & ~PORT_RWC_BITS) & ~PORT_PE, status_reg);
-               spin_unlock_irqrestore(&ehci->lock, flags);
-               return retval;
+               goto done;
        }
 
-       if (typeReq == GetPortStatus) {
-               spin_lock_irqsave(&ehci->lock, flags);
+       else if (typeReq == GetPortStatus) {
                temp = ehci_readl(ehci, status_reg);
-               if (tegra->port_resuming &&  !(temp & PORT_SUSPEND)) {
+               if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
                        /* resume completed */
                        tegra->port_resuming = 0;
                        tegra_usb_phy_postresume(tegra->phy);
                }
-               spin_unlock_irqrestore(&ehci->lock, flags);
        }
 
-       if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
-               spin_lock_irqsave(&ehci->lock, flags);
+       else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
                temp = ehci_readl(ehci, status_reg);
-               if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0)
+               if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
                        retval = -EPIPE;
+                       goto done;
+               }
 
                /* After above check the port must be connected.
                 * Set appropriate bit thus could put phy into low power
@@ -131,8 +130,7 @@ static int tegra_ehci_hub_control(
                if (handshake(ehci, status_reg, PORT_SUSPEND,
                                                PORT_SUSPEND, 5000))
                        pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__);
-               spin_unlock_irqrestore(&ehci->lock, flags);
-               return retval;
+               goto done;
        }
 
        /*
@@ -142,17 +140,16 @@ static int tegra_ehci_hub_control(
         * to set this bit to a zero after the resume duration is timed in the
         * driver.
         */
-       if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
-               spin_lock_irqsave(&ehci->lock, flags);
+       else if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
                temp = ehci_readl(ehci, status_reg);
-               if ((temp & PORT_RESET) || !(temp & PORT_PE))
+               if ((temp & PORT_RESET) || !(temp & PORT_PE)) {
                        retval = -EPIPE;
-
-               if (!(temp & PORT_SUSPEND)) {
-                       spin_unlock_irqrestore(&ehci->lock, flags);
-                       return retval;
+                       goto done;
                }
 
+               if (!(temp & PORT_SUSPEND))
+                       goto done;
+
                tegra_usb_phy_preresume(tegra->phy);
 
                /* reschedule root hub polling during resume signaling */
@@ -165,8 +162,12 @@ static int tegra_ehci_hub_control(
                /* start resume signalling */
                ehci_writel(ehci, temp | PORT_RESUME, status_reg);
 
+               spin_unlock_irqrestore(&ehci->lock, flags);
+               msleep(20);
+               spin_lock_irqsave(&ehci->lock, flags);
+
                /* polling PORT_RESUME until the controller clear this bit */
-               if (handshake(ehci, status_reg, PORT_RESUME, 0, 20000))
+               if (handshake(ehci, status_reg, PORT_RESUME, 0, 2000))
                        pr_err("%s: timeout waiting for PORT_RESUME\n", __func__);
 
                /* write PORT_RESUME to 0 to clear PORT_SUSPEND bit */
@@ -178,13 +179,16 @@ static int tegra_ehci_hub_control(
                        pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__);
 
                tegra->port_resuming = 1;
-
-               spin_unlock_irqrestore(&ehci->lock, flags);
-               return retval;
+               goto done;
        }
 
+       spin_unlock_irqrestore(&ehci->lock, flags);
+
        /* Handle the hub control events here */
        return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+done:
+       spin_unlock_irqrestore(&ehci->lock, flags);
+       return retval;
 }
 
 static void tegra_ehci_restart(struct usb_hcd *hcd)