Revert "USB: don't explicitly reenable root-hub status interrupts"
This reverts commit e872154921
.
Andrey Borzenkov reports that it resulted in a totally hung machine for
him when loading the OHCI driver. Extensive netconsole capture with
SysRq output shows that modprobe gets stuck in ohci_hub_status_data()
when probing and enabling the OHCI controller, see for example
http://lkml.org/lkml/2008/7/5/236
for an analysis.
The problem appears to be an interrupt flood triggered by the commit
that gets reverted, and Andrey confirmed that the revert makes things
work for him again.
Reported-and-tested-by: Andrey Borzenkov <arvidjaar@mail.ru>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: David Brownell <david-b@pacbell.net>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
@@ -36,6 +36,18 @@
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* hcd->hub_irq_enable() */
|
||||
static void ohci_rhsc_enable (struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
|
||||
|
||||
spin_lock_irq(&ohci->lock);
|
||||
if (!ohci->autostop)
|
||||
del_timer(&hcd->rh_timer); /* Prevent next poll */
|
||||
ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
|
||||
spin_unlock_irq(&ohci->lock);
|
||||
}
|
||||
|
||||
#define OHCI_SCHED_ENABLES \
|
||||
(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
|
||||
|
||||
@@ -362,28 +374,18 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
|
||||
int any_connected)
|
||||
{
|
||||
int poll_rh = 1;
|
||||
int rhsc;
|
||||
|
||||
rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC;
|
||||
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
|
||||
|
||||
case OHCI_USB_OPER:
|
||||
/* If no status changes are pending, enable status-change
|
||||
* interrupts.
|
||||
*/
|
||||
if (!rhsc && !changed) {
|
||||
rhsc = OHCI_INTR_RHSC;
|
||||
ohci_writel(ohci, rhsc, &ohci->regs->intrenable);
|
||||
}
|
||||
|
||||
/* Keep on polling until we know a device is connected
|
||||
* and RHSC is enabled, or until we autostop.
|
||||
*/
|
||||
/* keep on polling until we know a device is connected
|
||||
* and RHSC is enabled */
|
||||
if (!ohci->autostop) {
|
||||
if (any_connected ||
|
||||
!device_may_wakeup(&ohci_to_hcd(ohci)
|
||||
->self.root_hub->dev)) {
|
||||
if (rhsc)
|
||||
if (ohci_readl(ohci, &ohci->regs->intrenable) &
|
||||
OHCI_INTR_RHSC)
|
||||
poll_rh = 0;
|
||||
} else {
|
||||
ohci->autostop = 1;
|
||||
@@ -396,13 +398,12 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
|
||||
ohci->autostop = 0;
|
||||
ohci->next_statechange = jiffies +
|
||||
STATECHANGE_DELAY;
|
||||
} else if (rhsc && time_after_eq(jiffies,
|
||||
} else if (time_after_eq(jiffies,
|
||||
ohci->next_statechange)
|
||||
&& !ohci->ed_rm_list
|
||||
&& !(ohci->hc_control &
|
||||
OHCI_SCHED_ENABLES)) {
|
||||
ohci_rh_suspend(ohci, 1);
|
||||
poll_rh = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -416,12 +417,6 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
|
||||
else
|
||||
usb_hcd_resume_root_hub(ohci_to_hcd(ohci));
|
||||
} else {
|
||||
if (!rhsc && (ohci->autostop ||
|
||||
ohci_to_hcd(ohci)->self.root_hub->
|
||||
do_remote_wakeup))
|
||||
ohci_writel(ohci, OHCI_INTR_RHSC,
|
||||
&ohci->regs->intrenable);
|
||||
|
||||
/* everything is idle, no need for polling */
|
||||
poll_rh = 0;
|
||||
}
|
||||
@@ -443,16 +438,12 @@ static inline int ohci_rh_resume(struct ohci_hcd *ohci)
|
||||
static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
|
||||
int any_connected)
|
||||
{
|
||||
/* If RHSC is enabled, don't poll */
|
||||
if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
|
||||
return 0;
|
||||
int poll_rh = 1;
|
||||
|
||||
/* If no status changes are pending, enable status-change interrupts */
|
||||
if (!changed) {
|
||||
ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
/* keep on polling until RHSC is enabled */
|
||||
if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC)
|
||||
poll_rh = 0;
|
||||
return poll_rh;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
Reference in New Issue
Block a user