Kyle McMartin b8f320f
commit e17a07a9e0b62d5a5f0a5683ecbabad3aa95a4d5
Kyle McMartin b8f320f
Author: Matthew Garrett <mjg@redhat.com>
Kyle McMartin b8f320f
Date:   Tue Jan 11 12:19:40 2011 -0500
Kyle McMartin b8f320f
Kyle McMartin b8f320f
    ehci: Check individual port status registers on resume
Kyle McMartin b8f320f
    
Kyle McMartin b8f320f
    If a device plug/unplug is detected on an ATI SB700 USB controller in D3,
Kyle McMartin b8f320f
    it appears to set the port status register but not the controller status
Kyle McMartin b8f320f
    register. As a result we'll fail to detect the plug event. Check the port
Kyle McMartin b8f320f
    status register on resume as well in order to catch this case.
Kyle McMartin b8f320f
    
Kyle McMartin b8f320f
    Signed-off-by: Matthew Garrett <mjg@redhat.com>
Kyle McMartin b8f320f
Kyle McMartin b8f320f
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
Kyle McMartin b8f320f
index 796ea0c..d9c0748 100644
Kyle McMartin b8f320f
--- a/drivers/usb/host/ehci-hub.c
Kyle McMartin b8f320f
+++ b/drivers/usb/host/ehci-hub.c
Kyle McMartin b8f320f
@@ -106,6 +106,27 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
Kyle McMartin b8f320f
 	ehci->owned_ports = 0;
Kyle McMartin b8f320f
 }
Kyle McMartin b8f320f
 
Kyle McMartin b8f320f
+static int ehci_port_change(struct ehci_hcd *ehci)
Kyle McMartin b8f320f
+{
Kyle McMartin b8f320f
+	int i = HCS_N_PORTS(ehci->hcs_params);
Kyle McMartin b8f320f
+
Kyle McMartin b8f320f
+	/* First check if the controller indicates a change event */
Kyle McMartin b8f320f
+
Kyle McMartin b8f320f
+	if (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)
Kyle McMartin b8f320f
+		return 1;
Kyle McMartin b8f320f
+
Kyle McMartin b8f320f
+	/*
Kyle McMartin b8f320f
+	 * Not all controllers appear to update this while going from D3 to D0,
Kyle McMartin b8f320f
+	 * so check the individual port status registers as well
Kyle McMartin b8f320f
+	 */
Kyle McMartin b8f320f
+
Kyle McMartin b8f320f
+	while (i--)
Kyle McMartin b8f320f
+		if (ehci_readl(ehci, &ehci->regs->port_status[i]) & PORT_CSC)
Kyle McMartin b8f320f
+			return 1;
Kyle McMartin b8f320f
+
Kyle McMartin b8f320f
+	return 0;
Kyle McMartin b8f320f
+}
Kyle McMartin b8f320f
+
Kyle McMartin b8f320f
 static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
Kyle McMartin b8f320f
 		bool suspending, bool do_wakeup)
Kyle McMartin b8f320f
 {
Kyle McMartin b8f320f
@@ -168,7 +189,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
Kyle McMartin b8f320f
 	}
Kyle McMartin b8f320f
 
Kyle McMartin b8f320f
 	/* Does the root hub have a port wakeup pending? */
Kyle McMartin b8f320f
-	if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD))
Kyle McMartin b8f320f
+	if (!suspending && ehci_port_change(ehci))
Kyle McMartin b8f320f
 		usb_hcd_resume_root_hub(ehci_to_hcd(ehci));
Kyle McMartin b8f320f
 
Chuck Ebbert bad79d2
 	spin_unlock_irqrestore(&ehci->lock, flags);