lkml.org 
[lkml]   [2010]   [Jan]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[09/11] USB: EHCI & UHCI: fix race between root-hub suspend and port resume
    2.6.27-stable review patch.  If anyone has any objections, please let us know.

    ------------------

    From: Alan Stern <stern@rowland.harvard.edu>

    commit cec3a53c7fe794237b582e8e77fc0e48465e65ee upstream.

    This patch (as1321) fixes a problem with EHCI and UHCI root-hub
    suspends: If the suspend occurs while a port is trying to resume, the
    resume doesn't finish and simply gets lost. When remote wakeup is
    enabled, this is undesirable behavior.

    The patch checks first to see if any port resumes are in progress, and
    if they are then it fails the root-hub suspend with -EBUSY.

    Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    drivers/usb/host/ehci-hub.c | 20 +++++++++++++++++++-
    drivers/usb/host/uhci-hcd.c | 15 ++++++++++++++-
    2 files changed, 33 insertions(+), 2 deletions(-)

    --- a/drivers/usb/host/ehci-hub.c
    +++ b/drivers/usb/host/ehci-hub.c
    @@ -119,9 +119,26 @@ static int ehci_bus_suspend (struct usb_
    del_timer_sync(&ehci->watchdog);
    del_timer_sync(&ehci->iaa_watchdog);

    - port = HCS_N_PORTS (ehci->hcs_params);
    spin_lock_irq (&ehci->lock);

    + /* Once the controller is stopped, port resumes that are already
    + * in progress won't complete. Hence if remote wakeup is enabled
    + * for the root hub and any ports are in the middle of a resume or
    + * 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;
    + }
    + }
    + }
    +
    /* stop schedules, clean any completed work */
    if (HC_IS_RUNNING(hcd->state)) {
    ehci_quiesce (ehci);
    @@ -137,6 +154,7 @@ static int ehci_bus_suspend (struct usb_
    */
    ehci->bus_suspended = 0;
    ehci->owned_ports = 0;
    + port = HCS_N_PORTS(ehci->hcs_params);
    while (port--) {
    u32 __iomem *reg = &ehci->regs->port_status [port];
    u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
    --- a/drivers/usb/host/uhci-hcd.c
    +++ b/drivers/usb/host/uhci-hcd.c
    @@ -750,7 +750,20 @@ static int uhci_rh_suspend(struct usb_hc
    spin_lock_irq(&uhci->lock);
    if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
    rc = -ESHUTDOWN;
    - else if (!uhci->dead)
    + else if (uhci->dead)
    + ; /* Dead controllers tell no tales */
    +
    + /* Once the controller is stopped, port resumes that are already
    + * in progress won't complete. Hence if remote wakeup is enabled
    + * for the root hub and any ports are in the middle of a resume or
    + * remote wakeup, we must fail the suspend.
    + */
    + else if (hcd->self.root_hub->do_remote_wakeup &&
    + uhci->resuming_ports) {
    + dev_dbg(uhci_dev(uhci), "suspend failed because a port "
    + "is resuming\n");
    + rc = -EBUSY;
    + } else
    suspend_rh(uhci, UHCI_RH_SUSPENDED);
    spin_unlock_irq(&uhci->lock);
    return rc;



    \
     
     \ /
      Last update: 2010-01-26 20:33    [W:4.101 / U:0.228 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site