diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2008-07-21 09:56:26 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-08-13 20:32:49 -0400 |
commit | 38b375d9610e2467cb793a84d17c6f65e44cdb39 (patch) | |
tree | baade98427207a0086b018b153947ae2da7a5802 | |
parent | fa41019c7aa172fde075849834409d23eb49f582 (diff) |
USB: OHCI: fix system hang caused by earlier patch
This patch (as1114) fixes a problem that was revealed by an earlier
patch (as1069b). Some broken controllers seem never to turn off their
RHCS interrupt status bit, even when told to do so. As a result they
generate an interrupt storm and hang the system.
The patch avoids enabling RHSC interrupt requests when the RHCS status
bit is already set. This should have no adverse affects on normal
controllers, since they won't set the status bit until a root-hub
status change actually occurs, in which case we wouldn't enable RHSC
interrupt requests anyway -- we would wait until the status change had
been processed and cleared.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Tested by: Andrey Borzenkov <arvidjaar@mail.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/host/ohci-hub.c | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index b56739221d11..d54183f1d701 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c | |||
@@ -483,6 +483,13 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
483 | length++; | 483 | length++; |
484 | } | 484 | } |
485 | 485 | ||
486 | /* Some broken controllers never turn off RHCS in the interrupt | ||
487 | * status register. For their sake we won't re-enable RHSC | ||
488 | * interrupts if the flag is already set. | ||
489 | */ | ||
490 | if (ohci_readl(ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) | ||
491 | changed = 1; | ||
492 | |||
486 | /* look at each port */ | 493 | /* look at each port */ |
487 | for (i = 0; i < ohci->num_ports; i++) { | 494 | for (i = 0; i < ohci->num_ports; i++) { |
488 | u32 status = roothub_portstatus (ohci, i); | 495 | u32 status = roothub_portstatus (ohci, i); |