Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69fff59d authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

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
9b37596a (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: default avatarAlan Stern <stern@rowland.harvard.edu>
Tested-by: default avatarManuel Lauss <manuel.lauss@googlemail.com>
CC: Rodolfo Giometti <giometti@linux.it>
CC: Olav Kongas <ok@artecdesign.ee>
CC: <stable@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d2389440
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -986,7 +986,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 */
	}

@@ -2128,9 +2128,6 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
		if (hcd->shared_hcd)
			set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);

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

+3 −1
Original line number Diff line number Diff line
@@ -777,8 +777,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;
	}
@@ -873,6 +874,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
		 */
+6 −2
Original line number Diff line number Diff line
@@ -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);
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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;
		}
+3 −1
Original line number Diff line number Diff line
@@ -764,6 +764,7 @@ 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;
	}

@@ -771,7 +772,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
	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) {
@@ -788,6 +789,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);
Loading