On Fri, 7 Feb 2014, Peter Chen wrote: > If the high-speed device does not enter full-speed idle after > wakeup on disconnect logic has effected, there will be an > unexpected disconnect wakeup interrupt due to the bus is still SE0. > > Signed-off-by: Peter Chen <peter.chen@xxxxxxxxxxxxx> > > Hi Alan, > > If you can't met this issue, it may due to your hardware enables > WKDN after detecting full-speed idle or the time between stop > SoF and enable WKDN is more than 3ms (You need to know when > the WKDN has really taken effect). Yes. However, I don't like the way your patch can increase the total time if several ports have to be put into suspend. Consider this patch instead. Alan Stern Index: usb-3.14/drivers/usb/host/ehci-hub.c =================================================================== --- usb-3.14.orig/drivers/usb/host/ehci-hub.c +++ usb-3.14/drivers/usb/host/ehci-hub.c @@ -238,6 +238,7 @@ static int ehci_bus_suspend (struct usb_ int port; int mask; int changed; + unsigned want_WKDISC; ehci_dbg(ehci, "suspend root hub\n"); @@ -272,6 +273,7 @@ static int ehci_bus_suspend (struct usb_ ehci->bus_suspended = 0; ehci->owned_ports = 0; changed = 0; + want_WKDISC = 0; port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; @@ -300,16 +302,48 @@ static int ehci_bus_suspend (struct usb_ } if (t1 != t2) { + /* + * Don't enable wake-on-disconnect until the bus has + * switched over to full-speed idle. + */ + if ((t2 & PORT_WKDISC_E) && + ehci_port_speed(ehci, t2) == + USB_PORT_STAT_HIGH_SPEED) { + t2 &= ~PORT_WKDISC_E; + want_WKDISC |= (1 << port); + } ehci_writel(ehci, t2, reg); changed = 1; } } + spin_unlock_irq(&ehci->lock); - if (changed && ehci->has_tdi_phy_lpm) { - spin_unlock_irq(&ehci->lock); - msleep(5); /* 5 ms for HCD to enter low-power mode */ + if ((changed && ehci->has_tdi_phy_lpm) || want_WKDISC) { + /* + * Wait for HCD to enter low-power mode or for the bus + * to switch to full-speed idle. + */ + usleep_range(5000, 5500); + } + + if (want_WKDISC) { spin_lock_irq(&ehci->lock); + port = HCS_N_PORTS(ehci->hcs_params); + while (port--) { + u32 __iomem *reg; + u32 t2; + if (!(want_WKDISC & (1 << port))) + continue; + reg = &ehci->regs->port_status[port]; + t2 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; + ehci_writel(ehci, t2 | PORT_WKDISC_E, reg); + } + spin_unlock_irq(&ehci->lock); + } + + if (changed && ehci->has_tdi_phy_lpm) { + spin_lock_irq(&ehci->lock); port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port]; @@ -322,8 +356,8 @@ static int ehci_bus_suspend (struct usb_ port, (t3 & HOSTPC_PHCD) ? "succeeded" : "failed"); } + spin_unlock_irq(&ehci->lock); } - spin_unlock_irq(&ehci->lock); /* Apparently some devices need a >= 1-uframe delay here */ if (ehci->bus_suspended) -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html