Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

authored by

Alan Stern and committed by
Greg Kroah-Hartman
5c12e785 a6eeeb9f

+36 -34
+36 -34
drivers/usb/host/uhci-hcd.c
··· 294 294 * and that remote wakeups should be enabled. 295 295 */ 296 296 egsm_enable = USBCMD_EGSM; 297 - uhci->RD_enable = 1; 298 297 int_enable = USBINTR_RESUME; 299 298 wakeup_enable = 1; 300 299 301 - /* In auto-stop mode wakeups must always be detected, but 302 - * Resume-Detect interrupts may be prohibited. (In the absence 303 - * of CONFIG_PM, they are always disallowed.) 300 + /* 301 + * In auto-stop mode, we must be able to detect new connections. 302 + * The user can force us to poll by disabling remote wakeup; 303 + * otherwise we will use the EGSM/RD mechanism. 304 304 */ 305 305 if (auto_stop) { 306 306 if (!device_may_wakeup(&rhdev->dev)) 307 - int_enable = 0; 308 - 309 - /* In bus-suspend mode wakeups may be disabled, but if they are 310 - * allowed then so are Resume-Detect interrupts. 311 - */ 312 - } else { 313 - #ifdef CONFIG_PM 314 - if (!rhdev->do_remote_wakeup) 315 - wakeup_enable = 0; 316 - #endif 307 + egsm_enable = int_enable = 0; 317 308 } 318 309 319 - /* EGSM causes the root hub to echo a 'K' signal (resume) out any 320 - * port which requests a remote wakeup. According to the USB spec, 321 - * every hub is supposed to do this. But if we are ignoring 322 - * remote-wakeup requests anyway then there's no point to it. 323 - * We also shouldn't enable EGSM if it's broken. 310 + #ifdef CONFIG_PM 311 + /* 312 + * In bus-suspend mode, we use the wakeup setting specified 313 + * for the root hub. 324 314 */ 325 - if (!wakeup_enable || global_suspend_mode_is_broken(uhci)) 326 - egsm_enable = 0; 315 + else { 316 + if (!rhdev->do_remote_wakeup) 317 + wakeup_enable = 0; 318 + } 319 + #endif 327 320 328 - /* If we're ignoring wakeup events then there's no reason to 329 - * enable Resume-Detect interrupts. We also shouldn't enable 330 - * them if they are broken or disallowed. 321 + /* 322 + * UHCI doesn't distinguish between wakeup requests from downstream 323 + * devices and local connect/disconnect events. There's no way to 324 + * enable one without the other; both are controlled by EGSM. Thus 325 + * if wakeups are disallowed then EGSM must be turned off -- in which 326 + * case remote wakeup requests from downstream during system sleep 327 + * will be lost. 331 328 * 332 - * This logic may lead us to enabling RD but not EGSM. The UHCI 333 - * spec foolishly says that RD works only when EGSM is on, but 334 - * there's no harm in enabling it anyway -- perhaps some chips 335 - * will implement it! 329 + * In addition, if EGSM is broken then we can't use it. Likewise, 330 + * if Resume-Detect interrupts are broken then we can't use them. 331 + * 332 + * Finally, neither EGSM nor RD is useful by itself. Without EGSM, 333 + * the RD status bit will never get set. Without RD, the controller 334 + * won't generate interrupts to tell the system about wakeup events. 336 335 */ 337 - if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) || 338 - !int_enable) 339 - uhci->RD_enable = int_enable = 0; 336 + if (!wakeup_enable || global_suspend_mode_is_broken(uhci) || 337 + resume_detect_interrupts_are_broken(uhci)) 338 + egsm_enable = int_enable = 0; 340 339 340 + uhci->RD_enable = !!int_enable; 341 341 uhci_writew(uhci, int_enable, USBINTR); 342 342 uhci_writew(uhci, egsm_enable | USBCMD_CF, USBCMD); 343 343 mb(); ··· 364 364 uhci->rh_state = new_state; 365 365 uhci->is_stopped = UHCI_IS_STOPPED; 366 366 367 - /* If interrupts don't work and remote wakeup is enabled then 368 - * the suspended root hub needs to be polled. 367 + /* 368 + * If remote wakeup is enabled but either EGSM or RD interrupts 369 + * doesn't work, then we won't get an interrupt when a wakeup event 370 + * occurs. Thus the suspended root hub needs to be polled. 369 371 */ 370 - if (!int_enable && wakeup_enable) 372 + if (wakeup_enable && (!int_enable || !egsm_enable)) 371 373 set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags); 372 374 else 373 375 clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);