aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-10-09 15:40:23 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2008-10-17 17:41:04 -0400
commit71b7497c078a97e2afb774ad7c1f8ff5bdda8a60 (patch)
tree149cf8cdb985760ef2afea54bfc5181088311caa /drivers
parent8b6346ec899713a90890c9e832f7eff91ea73504 (diff)
USB: OHCI: fix endless polling behavior
This patch (as1149) fixes an obscure problem in OHCI polling. In the current code, if the RHSC interrupt status flag turns on at a time when RHSC interrupts are disabled, it will remain on forever: The interrupt handler is the only place where RHSC status gets turned back off; The interrupt handler won't turn RHSC status off because it doesn't turn off status flags if the corresponding interrupt isn't enabled; RHSC interrupts will never get enabled because ohci_root_hub_state_changes() doesn't reenable RHSC if RHSC status is on! As a result we will continue polling indefinitely instead of reverting to interrupt-driven operation, and the root hub will not autosuspend. This particular sequence of events is not at all unusual; in fact plugging a USB device into an OHCI controller will usually cause it to occur. Of course, this is a bug. The proper thing to do is to turn off RHSC status just before reading the actual port status values. That way either a port status change will be detected (if it occurs before the status read) or it will turn RHSC back on. Possibly both, but that won't hurt anything. We can still check for systems in which RHSC is totally broken, by re-reading RHSC after clearing it and before reading the port statuses. (This re-read has to be done anyway, to post the earlier write.) If RHSC is on but no port-change statuses are set, then we know that RHSC is broken and we can avoid re-enabling it. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ohci-hub.c51
1 files changed, 32 insertions, 19 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index a150e85c901a..32bbce9718f0 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -359,17 +359,15 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd)
359 359
360/* Carry out polling-, autostop-, and autoresume-related state changes */ 360/* Carry out polling-, autostop-, and autoresume-related state changes */
361static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, 361static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
362 int any_connected) 362 int any_connected, int rhsc_status)
363{ 363{
364 int poll_rh = 1; 364 int poll_rh = 1;
365 int rhsc_status, rhsc_enable; 365 int rhsc_enable;
366 366
367 /* Some broken controllers never turn off RHCS in the interrupt 367 /* Some broken controllers never turn off RHCS in the interrupt
368 * status register. For their sake we won't re-enable RHSC 368 * status register. For their sake we won't re-enable RHSC
369 * interrupts if the interrupt bit is already active. 369 * interrupts if the interrupt bit is already active.
370 */ 370 */
371 rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
372 OHCI_INTR_RHSC;
373 rhsc_enable = ohci_readl(ohci, &ohci->regs->intrenable) & 371 rhsc_enable = ohci_readl(ohci, &ohci->regs->intrenable) &
374 OHCI_INTR_RHSC; 372 OHCI_INTR_RHSC;
375 373
@@ -421,14 +419,23 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
421 ohci_rh_resume(ohci); 419 ohci_rh_resume(ohci);
422 else 420 else
423 usb_hcd_resume_root_hub(ohci_to_hcd(ohci)); 421 usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
422
423 /* If remote wakeup is disabled, stop polling */
424 } else if (!ohci->autostop &&
425 !ohci_to_hcd(ohci)->self.root_hub->
426 do_remote_wakeup) {
427 poll_rh = 0;
428
424 } else { 429 } else {
425 if (!rhsc_enable && !rhsc_status && (ohci->autostop || 430 /* If no status changes are pending,
426 ohci_to_hcd(ohci)->self.root_hub-> 431 * enable RHSC interrupts
427 do_remote_wakeup)) { 432 */
433 if (!rhsc_enable && !rhsc_status) {
428 rhsc_enable = OHCI_INTR_RHSC; 434 rhsc_enable = OHCI_INTR_RHSC;
429 ohci_writel(ohci, rhsc_enable, 435 ohci_writel(ohci, rhsc_enable,
430 &ohci->regs->intrenable); 436 &ohci->regs->intrenable);
431 } 437 }
438 /* Keep polling until RHSC is enabled */
432 if (rhsc_enable) 439 if (rhsc_enable)
433 poll_rh = 0; 440 poll_rh = 0;
434 } 441 }
@@ -448,22 +455,22 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
448 * autostop isn't used when CONFIG_PM is turned off. 455 * autostop isn't used when CONFIG_PM is turned off.
449 */ 456 */
450static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, 457static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
451 int any_connected) 458 int any_connected, int rhsc_status)
452{ 459{
453 int rhsc_status;
454
455 /* If RHSC is enabled, don't poll */ 460 /* If RHSC is enabled, don't poll */
456 if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC) 461 if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
457 return 0; 462 return 0;
458 463
459 /* If no status changes are pending, enable RHSC interrupts */ 464 /* If status changes are pending, continue polling.
460 rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) & 465 * Conversely, if no status changes are pending but the RHSC
461 OHCI_INTR_RHSC; 466 * status bit was set, then RHSC may be broken so continue polling.
462 if (!changed && !rhsc_status) { 467 */
463 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); 468 if (changed || rhsc_status)
464 return 0; 469 return 1;
465 } 470
466 return 1; 471 /* It's safe to re-enable RHSC interrupts */
472 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
473 return 0;
467} 474}
468 475
469#endif /* CONFIG_PM */ 476#endif /* CONFIG_PM */
@@ -478,6 +485,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
478 struct ohci_hcd *ohci = hcd_to_ohci (hcd); 485 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
479 int i, changed = 0, length = 1; 486 int i, changed = 0, length = 1;
480 int any_connected = 0; 487 int any_connected = 0;
488 int rhsc_status;
481 unsigned long flags; 489 unsigned long flags;
482 490
483 spin_lock_irqsave (&ohci->lock, flags); 491 spin_lock_irqsave (&ohci->lock, flags);
@@ -503,6 +511,11 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
503 length++; 511 length++;
504 } 512 }
505 513
514 /* Clear the RHSC status flag before reading the port statuses */
515 ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrstatus);
516 rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) &
517 OHCI_INTR_RHSC;
518
506 /* look at each port */ 519 /* look at each port */
507 for (i = 0; i < ohci->num_ports; i++) { 520 for (i = 0; i < ohci->num_ports; i++) {
508 u32 status = roothub_portstatus (ohci, i); 521 u32 status = roothub_portstatus (ohci, i);
@@ -521,7 +534,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
521 } 534 }
522 535
523 hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed, 536 hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed,
524 any_connected); 537 any_connected, rhsc_status);
525 538
526done: 539done:
527 spin_unlock_irqrestore (&ohci->lock, flags); 540 spin_unlock_irqrestore (&ohci->lock, flags);