aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2011-09-26 11:25:26 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-09-26 18:58:18 -0400
commit5c12e7856d75f68c1ca8372d6cc76cdbc71763c0 (patch)
treee51e149490c5a7607a5f6d8f7e60b8082b657be3 /drivers/usb/host
parenta6eeeb9f45b5a417f574f3bc799b7122270bf59b (diff)
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>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/uhci-hcd.c66
1 files changed, 34 insertions, 32 deletions
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index fba99b120588..c8ae199cfbb8 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -294,50 +294,50 @@ __acquires(uhci->lock)
294 * and that remote wakeups should be enabled. 294 * and that remote wakeups should be enabled.
295 */ 295 */
296 egsm_enable = USBCMD_EGSM; 296 egsm_enable = USBCMD_EGSM;
297 uhci->RD_enable = 1;
298 int_enable = USBINTR_RESUME; 297 int_enable = USBINTR_RESUME;
299 wakeup_enable = 1; 298 wakeup_enable = 1;
300 299
301 /* In auto-stop mode wakeups must always be detected, but 300 /*
302 * Resume-Detect interrupts may be prohibited. (In the absence 301 * In auto-stop mode, we must be able to detect new connections.
303 * of CONFIG_PM, they are always disallowed.) 302 * The user can force us to poll by disabling remote wakeup;
303 * otherwise we will use the EGSM/RD mechanism.
304 */ 304 */
305 if (auto_stop) { 305 if (auto_stop) {
306 if (!device_may_wakeup(&rhdev->dev)) 306 if (!device_may_wakeup(&rhdev->dev))
307 int_enable = 0; 307 egsm_enable = int_enable = 0;
308 }
308 309
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 310#ifdef CONFIG_PM
311 /*
312 * In bus-suspend mode, we use the wakeup setting specified
313 * for the root hub.
314 */
315 else {
314 if (!rhdev->do_remote_wakeup) 316 if (!rhdev->do_remote_wakeup)
315 wakeup_enable = 0; 317 wakeup_enable = 0;
316#endif
317 } 318 }
319#endif
318 320
319 /* EGSM causes the root hub to echo a 'K' signal (resume) out any 321 /*
320 * port which requests a remote wakeup. According to the USB spec, 322 * UHCI doesn't distinguish between wakeup requests from downstream
321 * every hub is supposed to do this. But if we are ignoring 323 * devices and local connect/disconnect events. There's no way to
322 * remote-wakeup requests anyway then there's no point to it. 324 * enable one without the other; both are controlled by EGSM. Thus
323 * We also shouldn't enable EGSM if it's broken. 325 * if wakeups are disallowed then EGSM must be turned off -- in which
324 */ 326 * case remote wakeup requests from downstream during system sleep
325 if (!wakeup_enable || global_suspend_mode_is_broken(uhci)) 327 * will be lost.
326 egsm_enable = 0; 328 *
327 329 * In addition, if EGSM is broken then we can't use it. Likewise,
328 /* If we're ignoring wakeup events then there's no reason to 330 * if Resume-Detect interrupts are broken then we can't use them.
329 * enable Resume-Detect interrupts. We also shouldn't enable
330 * them if they are broken or disallowed.
331 * 331 *
332 * This logic may lead us to enabling RD but not EGSM. The UHCI 332 * Finally, neither EGSM nor RD is useful by itself. Without EGSM,
333 * spec foolishly says that RD works only when EGSM is on, but 333 * the RD status bit will never get set. Without RD, the controller
334 * there's no harm in enabling it anyway -- perhaps some chips 334 * won't generate interrupts to tell the system about wakeup events.
335 * will implement it!
336 */ 335 */
337 if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) || 336 if (!wakeup_enable || global_suspend_mode_is_broken(uhci) ||
338 !int_enable) 337 resume_detect_interrupts_are_broken(uhci))
339 uhci->RD_enable = int_enable = 0; 338 egsm_enable = int_enable = 0;
340 339
340 uhci->RD_enable = !!int_enable;
341 uhci_writew(uhci, int_enable, USBINTR); 341 uhci_writew(uhci, int_enable, USBINTR);
342 uhci_writew(uhci, egsm_enable | USBCMD_CF, USBCMD); 342 uhci_writew(uhci, egsm_enable | USBCMD_CF, USBCMD);
343 mb(); 343 mb();
@@ -364,10 +364,12 @@ __acquires(uhci->lock)
364 uhci->rh_state = new_state; 364 uhci->rh_state = new_state;
365 uhci->is_stopped = UHCI_IS_STOPPED; 365 uhci->is_stopped = UHCI_IS_STOPPED;
366 366
367 /* If interrupts don't work and remote wakeup is enabled then 367 /*
368 * the suspended root hub needs to be polled. 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 set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags); 373 set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
372 else 374 else
373 clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags); 375 clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);