> > > > ************************************************************************* > ************************************ > > Index: usb-3.3/drivers/usb/core/hcd.c > > =================================================================== > > --- usb-3.3.orig/drivers/usb/core/hcd.c > > +++ usb-3.3/drivers/usb/core/hcd.c > > @@ -1978,6 +1978,13 @@ int hcd_bus_suspend(struct usb_device *r > > if (status == 0) { > > usb_set_device_state(rhdev, USB_STATE_SUSPENDED); > > hcd->state = HC_STATE_SUSPENDED; > > + > > + /* Did we race with a root-hub wakeup event? */ > > + if (unlikely(HCD_POLL_PENDING(hcd) && > > + rhdev->do_remote_wakeup)) { > > + hcd_bus_resume(rhdev, PMSG_AUTO_RESUME); > > + status = -EBUSY; > > + } > > > > This patch may not useful, as if the remote wakeup occurs before the > bus(roothub) suspend > > (taking ehic_bus_suspend as an example), the bus suspend will quit due > to there is a resume > > signal at one port. If the remote wakeup occurs after bus suspend, but > before your patch, > > the HCD_FLAG_POLL_PENDING will not be set due to hcd->driver- > >hub_status_data returns 0 (taking > > ehci as an example), as this flag is set after 25ms later after remote > wakeup occurs. > > I promised an update for this patch, and here it is. The new version > requires changes to the HCD drivers. Basically, the HCD is now > required to return a non-zero value from the hub_status_data routine if > a resume is currently in progress on any port. The changes for > ehci-hcd are included as a separate patch below. > > Alan Stern > You may forget somewhere to set resuming_ports, a patch like below may be needed. diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index a007a9f..3f8a67f 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -941,6 +941,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) */ ehci->reset_done[i] = jiffies + msecs_to_jiffies(25); ehci_dbg (ehci, "port %d remote wakeup\n", i + 1); + set_bit(i, &ehci->resuming_ports); mod_timer(&hcd->rh_timer, ehci->reset_done[i]); } } > > > Index: usb-3.3/drivers/usb/core/hcd.c > =================================================================== > --- usb-3.3.orig/drivers/usb/core/hcd.c > +++ usb-3.3/drivers/usb/core/hcd.c > @@ -1978,6 +1978,18 @@ int hcd_bus_suspend(struct usb_device *r > if (status == 0) { > usb_set_device_state(rhdev, USB_STATE_SUSPENDED); > hcd->state = HC_STATE_SUSPENDED; > + > + /* Did we race with a root-hub wakeup event? */ > + if (rhdev->do_remote_wakeup) { > + char buffer[6]; > + > + status = hcd->driver->hub_status_data(hcd, buffer); > + if (status != 0) { > + dev_dbg(&rhdev->dev, "suspend raced with wakeup > event\n"); > + hcd_bus_resume(rhdev, PMSG_AUTO_RESUME); > + status = -EBUSY; > + } > + } > } else { > spin_lock_irq(&hcd_root_hub_lock); > if (!HCD_DEAD(hcd)) { > > > > > Index: usb-3.3/drivers/usb/host/ehci-hub.c > =================================================================== > --- usb-3.3.orig/drivers/usb/host/ehci-hub.c > +++ usb-3.3/drivers/usb/host/ehci-hub.c > @@ -223,15 +223,10 @@ static int ehci_bus_suspend (struct usb_ > * 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; > } > } > > @@ -554,16 +549,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); > @@ -572,6 +563,11 @@ ehci_hub_status_data (struct usb_hcd *hc > 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 > @@ -846,6 +842,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) { > @@ -864,6 +861,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), > @@ -884,8 +882,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) && > @@ -920,6 +920,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: usb-3.3/drivers/usb/host/ehci.h > =================================================================== > --- usb-3.3.orig/drivers/usb/host/ehci.h > +++ usb-3.3/drivers/usb/host/ehci.h > @@ -117,6 +117,8 @@ struct ehci_hcd { /* one per > controlle > the change-suspend feature turned on */ > unsigned long suspended_ports; /* which ports are > suspended */ > + unsigned long resuming_ports; /* which ports have > + start to resume */ > > /* per-HC memory pools (could be per-bus, but ...) */ > struct dma_pool *qh_pool; /* qh per active urb */ > -- 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