mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-28 23:24:50 +00:00
USB: remove remaining usages of hcd->state from usbcore and fix regression
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
9b37596a2e
(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 <stern@rowland.harvard.edu>
Tested-by: Manuel Lauss <manuel.lauss@googlemail.com>
CC: Rodolfo Giometti <giometti@linux.it>
CC: Olav Kongas <ok@artecdesign.ee>
CC: <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
d23894402b
commit
69fff59de4
6 changed files with 19 additions and 9 deletions
|
@ -986,7 +986,7 @@ static int register_root_hub(struct usb_hcd *hcd)
|
||||||
spin_unlock_irq (&hcd_root_hub_lock);
|
spin_unlock_irq (&hcd_root_hub_lock);
|
||||||
|
|
||||||
/* Did the HC die before the root hub was registered? */
|
/* 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 */
|
usb_hc_died (hcd); /* This time clean up */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2128,9 +2128,6 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
|
||||||
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
|
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
|
||||||
if (hcd->shared_hcd)
|
if (hcd->shared_hcd)
|
||||||
set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
|
set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
|
||||||
|
|
||||||
if (unlikely(hcd->state == HC_STATE_HALT))
|
|
||||||
usb_hc_died(hcd);
|
|
||||||
rc = IRQ_HANDLED;
|
rc = IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -777,8 +777,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
||||||
goto dead;
|
goto dead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Shared IRQ? */
|
||||||
masked_status = status & INTR_MASK;
|
masked_status = status & INTR_MASK;
|
||||||
if (!masked_status) { /* irq sharing? */
|
if (!masked_status || unlikely(hcd->state == HC_STATE_HALT)) {
|
||||||
spin_unlock(&ehci->lock);
|
spin_unlock(&ehci->lock);
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
@ -873,6 +874,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
|
||||||
dead:
|
dead:
|
||||||
ehci_reset(ehci);
|
ehci_reset(ehci);
|
||||||
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
|
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
|
||||||
|
usb_hc_died(hcd);
|
||||||
/* generic layer kills/unlinks all urbs, then
|
/* generic layer kills/unlinks all urbs, then
|
||||||
* uses ehci_stop to clean up the rest
|
* uses ehci_stop to clean up the rest
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -471,8 +471,10 @@ static int enable_periodic (struct ehci_hcd *ehci)
|
||||||
*/
|
*/
|
||||||
status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
|
status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
|
||||||
STS_PSS, 0, 9 * 125);
|
STS_PSS, 0, 9 * 125);
|
||||||
if (status)
|
if (status) {
|
||||||
|
usb_hc_died(ehci_to_hcd(ehci));
|
||||||
return status;
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
|
cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
|
||||||
ehci_writel(ehci, cmd, &ehci->regs->command);
|
ehci_writel(ehci, cmd, &ehci->regs->command);
|
||||||
|
@ -510,8 +512,10 @@ static int disable_periodic (struct ehci_hcd *ehci)
|
||||||
*/
|
*/
|
||||||
status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
|
status = handshake_on_error_set_halt(ehci, &ehci->regs->status,
|
||||||
STS_PSS, STS_PSS, 9 * 125);
|
STS_PSS, STS_PSS, 9 * 125);
|
||||||
if (status)
|
if (status) {
|
||||||
|
usb_hc_died(ehci_to_hcd(ehci));
|
||||||
return status;
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
|
cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
|
||||||
ehci_writel(ehci, cmd, &ehci->regs->command);
|
ehci_writel(ehci, cmd, &ehci->regs->command);
|
||||||
|
|
|
@ -612,6 +612,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd)
|
||||||
/* IRQ's are off, we do no DMA,
|
/* IRQ's are off, we do no DMA,
|
||||||
perfectly ready to die ... */
|
perfectly ready to die ... */
|
||||||
hcd->state = HC_STATE_HALT;
|
hcd->state = HC_STATE_HALT;
|
||||||
|
usb_hc_died(hcd);
|
||||||
ret = IRQ_HANDLED;
|
ret = IRQ_HANDLED;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
|
@ -764,6 +764,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
||||||
if (ints == ~(u32)0) {
|
if (ints == ~(u32)0) {
|
||||||
disable (ohci);
|
disable (ohci);
|
||||||
ohci_dbg (ohci, "device removed!\n");
|
ohci_dbg (ohci, "device removed!\n");
|
||||||
|
usb_hc_died(hcd);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,7 +772,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
||||||
ints &= ohci_readl(ohci, ®s->intrenable);
|
ints &= ohci_readl(ohci, ®s->intrenable);
|
||||||
|
|
||||||
/* interrupt for some other device? */
|
/* interrupt for some other device? */
|
||||||
if (ints == 0)
|
if (ints == 0 || unlikely(hcd->state == HC_STATE_HALT))
|
||||||
return IRQ_NOTMINE;
|
return IRQ_NOTMINE;
|
||||||
|
|
||||||
if (ints & OHCI_INTR_UE) {
|
if (ints & OHCI_INTR_UE) {
|
||||||
|
@ -788,6 +789,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
|
||||||
} else {
|
} else {
|
||||||
disable (ohci);
|
disable (ohci);
|
||||||
ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
|
ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
|
||||||
|
usb_hc_died(hcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
ohci_dump (ohci, 1);
|
ohci_dump (ohci, 1);
|
||||||
|
|
|
@ -1884,6 +1884,7 @@ static int enable_periodic(struct oxu_hcd *oxu)
|
||||||
status = handshake(oxu, &oxu->regs->status, STS_PSS, 0, 9 * 125);
|
status = handshake(oxu, &oxu->regs->status, STS_PSS, 0, 9 * 125);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
oxu_to_hcd(oxu)->state = HC_STATE_HALT;
|
oxu_to_hcd(oxu)->state = HC_STATE_HALT;
|
||||||
|
usb_hc_died(oxu_to_hcd(oxu));
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1909,6 +1910,7 @@ static int disable_periodic(struct oxu_hcd *oxu)
|
||||||
status = handshake(oxu, &oxu->regs->status, STS_PSS, STS_PSS, 9 * 125);
|
status = handshake(oxu, &oxu->regs->status, STS_PSS, STS_PSS, 9 * 125);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
oxu_to_hcd(oxu)->state = HC_STATE_HALT;
|
oxu_to_hcd(oxu)->state = HC_STATE_HALT;
|
||||||
|
usb_hc_died(oxu_to_hcd(oxu));
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2449,8 +2451,9 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd)
|
||||||
goto dead;
|
goto dead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Shared IRQ? */
|
||||||
status &= INTR_MASK;
|
status &= INTR_MASK;
|
||||||
if (!status) { /* irq sharing? */
|
if (!status || unlikely(hcd->state == HC_STATE_HALT)) {
|
||||||
spin_unlock(&oxu->lock);
|
spin_unlock(&oxu->lock);
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
}
|
}
|
||||||
|
@ -2516,6 +2519,7 @@ static irqreturn_t oxu210_hcd_irq(struct usb_hcd *hcd)
|
||||||
dead:
|
dead:
|
||||||
ehci_reset(oxu);
|
ehci_reset(oxu);
|
||||||
writel(0, &oxu->regs->configured_flag);
|
writel(0, &oxu->regs->configured_flag);
|
||||||
|
usb_hc_died(hcd);
|
||||||
/* generic layer kills/unlinks all urbs, then
|
/* generic layer kills/unlinks all urbs, then
|
||||||
* uses oxu_stop to clean up the rest
|
* uses oxu_stop to clean up the rest
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue