Skip to content

Commit

Permalink
USB: remove remaining usages of hcd->state from usbcore and fix regre…
Browse files Browse the repository at this point in the history
…ssion

commit 69fff59 upstream.

This patch (as1467) removes the last usages of hcd->state from
usbcore.  We no longer check to see if an interrupt handler finds that
a controller has died; instead we rely on host controller drivers to
make an explicit call to usb_hc_died().

This fixes a regression introduced by commit
9b37596 (USB: move usbcore away from
hcd->state).  It used to be that when a controller shared an IRQ with
another device and an interrupt arrived while hcd->state was set to
HC_STATE_HALT, the interrupt handler would be skipped.  The commit
removed that test; as a result the current code doesn't skip calling
the handler and ends up believing the controller has died, even though
it's only temporarily stopped.  The solution is to ignore HC_STATE_HALT
following the handler's return.

As a consequence of this change, several of the host controller
drivers need to be modified.  They can no longer implicitly rely on
usbcore realizing that a controller has died because of hcd->state.
The patch adds calls to usb_hc_died() in the appropriate places.

The patch also changes a few of the interrupt handlers.  They don't
expect to be called when hcd->state is equal to HC_STATE_HALT, even if
the controller is still alive.  Early returns were added to avoid any
confusion.

Signed-off-by: Alan Stern <[email protected]>
Tested-by: Manuel Lauss <[email protected]>
CC: Rodolfo Giometti <[email protected]>
CC: Olav Kongas <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
AlanStern authored and gregkh committed Jun 3, 2011
1 parent a6cde63 commit d8fe024
Show file tree
Hide file tree
Showing 6 changed files with 19 additions and 9 deletions.
5 changes: 1 addition & 4 deletions drivers/usb/core/hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,7 @@ static int register_root_hub(struct usb_hcd *hcd)
spin_unlock_irq (&hcd_root_hub_lock);

/* Did the HC die before the root hub was registered? */
if (HCD_DEAD(hcd) || hcd->state == HC_STATE_HALT)
if (HCD_DEAD(hcd))
usb_hc_died (hcd); /* This time clean up */
}

Expand Down Expand Up @@ -2103,9 +2103,6 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
rc = IRQ_NONE;
} else {
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);

if (unlikely(hcd->state == HC_STATE_HALT))
usb_hc_died(hcd);
rc = IRQ_HANDLED;
}

Expand Down
4 changes: 3 additions & 1 deletion drivers/usb/host/ehci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -776,8 +776,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
goto dead;
}

/* Shared IRQ? */
masked_status = status & INTR_MASK;
if (!masked_status) { /* irq sharing? */
if (!masked_status || unlikely(hcd->state == HC_STATE_HALT)) {
spin_unlock(&ehci->lock);
return IRQ_NONE;
}
Expand Down Expand Up @@ -872,6 +873,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
dead:
ehci_reset(ehci);
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
usb_hc_died(hcd);
/* generic layer kills/unlinks all urbs, then
* uses ehci_stop to clean up the rest
*/
Expand Down
8 changes: 6 additions & 2 deletions drivers/usb/host/ehci-sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -471,8 +471,10 @@ static int enable_periodic (struct ehci_hcd *ehci)
*/
status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
STS_PSS, 0, 9 * 125);
if (status)
if (status) {
usb_hc_died(ehci_to_hcd(ehci));
return status;
}

cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
ehci_writel(ehci, cmd, &ehci->regs->command);
Expand Down Expand Up @@ -510,8 +512,10 @@ static int disable_periodic (struct ehci_hcd *ehci)
*/
status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
STS_PSS, STS_PSS, 9 * 125);
if (status)
if (status) {
usb_hc_died(ehci_to_hcd(ehci));
return status;
}

cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
ehci_writel(ehci, cmd, &ehci->regs->command);
Expand Down
1 change: 1 addition & 0 deletions drivers/usb/host/isp116x-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd)
/* IRQ's are off, we do no DMA,
perfectly ready to die ... */
hcd->state = HC_STATE_HALT;
usb_hc_died(hcd);
ret = IRQ_HANDLED;
goto done;
}
Expand Down
4 changes: 3 additions & 1 deletion drivers/usb/host/ohci-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -773,14 +773,15 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
if (ints == ~(u32)0) {
disable (ohci);
ohci_dbg (ohci, "device removed!\n");
usb_hc_died(hcd);
return IRQ_HANDLED;
}

/* We only care about interrupts that are enabled */
ints &= ohci_readl(ohci, &regs->intrenable);

/* interrupt for some other device? */
if (ints == 0)
if (ints == 0 || unlikely(hcd->state == HC_STATE_HALT))
return IRQ_NOTMINE;

if (ints & OHCI_INTR_UE) {
Expand All @@ -797,6 +798,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
} else {
disable (ohci);
ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
usb_hc_died(hcd);
}

ohci_dump (ohci, 1);
Expand Down
6 changes: 5 additions & 1 deletion drivers/usb/host/oxu210hp-hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,7 @@ static int enable_periodic(struct oxu_hcd *oxu)
status = handshake(oxu, &oxu->regs->status, STS_PSS, 0, 9 * 125);
if (status != 0) {
oxu_to_hcd(oxu)->state = HC_STATE_HALT;
usb_hc_died(oxu_to_hcd(oxu));
return status;
}

Expand All @@ -1909,6 +1910,7 @@ static int disable_periodic(struct oxu_hcd *oxu)
status = handshake(oxu, &oxu->regs->status, STS_PSS, STS_PSS, 9 * 125);
if (status != 0) {
oxu_to_hcd(oxu)->state = HC_STATE_HALT;
usb_hc_died(oxu_to_hcd(oxu));
return status;
}

Expand Down Expand Up @@ -2449,8 +2451,9 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd)
goto dead;
}

/* Shared IRQ? */
status &= INTR_MASK;
if (!status) { /* irq sharing? */
if (!status || unlikely(hcd->state == HC_STATE_HALT)) {
spin_unlock(&oxu->lock);
return IRQ_NONE;
}
Expand Down Expand Up @@ -2516,6 +2519,7 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd)
dead:
ehci_reset(oxu);
writel(0, &oxu->regs->configured_flag);
usb_hc_died(hcd);
/* generic layer kills/unlinks all urbs, then
* uses oxu_stop to clean up the rest
*/
Expand Down

0 comments on commit d8fe024

Please sign in to comment.