Commit 5c12e785 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: UHCI: improve comments and logic for root-hub suspend

This patch (as1488) improves the comments and logic in uhci-hcd's
suspend routine.  The existing comments are hard to understand and
don't give a good idea of what's really going on.

The question of whether EGSM (Enter Global Suspend Mode) and RD
(enable Resume Detect interrupts) can be useful when they're not both
set is difficult.  The spec doesn't give any details on how they
interact with system wakeup, although clearly they are meant to be
used together.  To be safe, the patch changes the subroutine so that
neither bit gets set unless they both do.  There shouldn't be any
functional changes from this; only systems that are designed badly or
broken in some way need to avoid using those bits.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent a6eeeb9f
...@@ -294,50 +294,50 @@ __acquires(uhci->lock) ...@@ -294,50 +294,50 @@ __acquires(uhci->lock)
* and that remote wakeups should be enabled. * and that remote wakeups should be enabled.
*/ */
egsm_enable = USBCMD_EGSM; egsm_enable = USBCMD_EGSM;
uhci->RD_enable = 1;
int_enable = USBINTR_RESUME; int_enable = USBINTR_RESUME;
wakeup_enable = 1; wakeup_enable = 1;
/* In auto-stop mode wakeups must always be detected, but /*
* Resume-Detect interrupts may be prohibited. (In the absence * In auto-stop mode, we must be able to detect new connections.
* of CONFIG_PM, they are always disallowed.) * The user can force us to poll by disabling remote wakeup;
* otherwise we will use the EGSM/RD mechanism.
*/ */
if (auto_stop) { if (auto_stop) {
if (!device_may_wakeup(&rhdev->dev)) if (!device_may_wakeup(&rhdev->dev))
int_enable = 0; egsm_enable = int_enable = 0;
}
/* In bus-suspend mode wakeups may be disabled, but if they are
* allowed then so are Resume-Detect interrupts.
*/
} else {
#ifdef CONFIG_PM #ifdef CONFIG_PM
/*
* In bus-suspend mode, we use the wakeup setting specified
* for the root hub.
*/
else {
if (!rhdev->do_remote_wakeup) if (!rhdev->do_remote_wakeup)
wakeup_enable = 0; wakeup_enable = 0;
#endif
} }
#endif
/* EGSM causes the root hub to echo a 'K' signal (resume) out any /*
* port which requests a remote wakeup. According to the USB spec, * UHCI doesn't distinguish between wakeup requests from downstream
* every hub is supposed to do this. But if we are ignoring * devices and local connect/disconnect events. There's no way to
* remote-wakeup requests anyway then there's no point to it. * enable one without the other; both are controlled by EGSM. Thus
* We also shouldn't enable EGSM if it's broken. * if wakeups are disallowed then EGSM must be turned off -- in which
*/ * case remote wakeup requests from downstream during system sleep
if (!wakeup_enable || global_suspend_mode_is_broken(uhci)) * will be lost.
egsm_enable = 0; *
* In addition, if EGSM is broken then we can't use it. Likewise,
/* If we're ignoring wakeup events then there's no reason to * if Resume-Detect interrupts are broken then we can't use them.
* enable Resume-Detect interrupts. We also shouldn't enable
* them if they are broken or disallowed.
* *
* This logic may lead us to enabling RD but not EGSM. The UHCI * Finally, neither EGSM nor RD is useful by itself. Without EGSM,
* spec foolishly says that RD works only when EGSM is on, but * the RD status bit will never get set. Without RD, the controller
* there's no harm in enabling it anyway -- perhaps some chips * won't generate interrupts to tell the system about wakeup events.
* will implement it!
*/ */
if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) || if (!wakeup_enable || global_suspend_mode_is_broken(uhci) ||
!int_enable) resume_detect_interrupts_are_broken(uhci))
uhci->RD_enable = int_enable = 0; egsm_enable = int_enable = 0;
uhci->RD_enable = !!int_enable;
uhci_writew(uhci, int_enable, USBINTR); uhci_writew(uhci, int_enable, USBINTR);
uhci_writew(uhci, egsm_enable | USBCMD_CF, USBCMD); uhci_writew(uhci, egsm_enable | USBCMD_CF, USBCMD);
mb(); mb();
...@@ -364,10 +364,12 @@ __acquires(uhci->lock) ...@@ -364,10 +364,12 @@ __acquires(uhci->lock)
uhci->rh_state = new_state; uhci->rh_state = new_state;
uhci->is_stopped = UHCI_IS_STOPPED; uhci->is_stopped = UHCI_IS_STOPPED;
/* If interrupts don't work and remote wakeup is enabled then /*
* the suspended root hub needs to be polled. * If remote wakeup is enabled but either EGSM or RD interrupts
* doesn't work, then we won't get an interrupt when a wakeup event
* occurs. Thus the suspended root hub needs to be polled.
*/ */
if (!int_enable && wakeup_enable) if (wakeup_enable && (!int_enable || !egsm_enable))
set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags); set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
else else
clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags); clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment