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

Commit 4cf8c454 authored by Chandana Kishori Chiluveru's avatar Chandana Kishori Chiluveru
Browse files

usb: host: xhci: Abort suspend when interrupt is pending



During xhci suspend driver disables interrupt, clears HW_ACCESSIBLE and
halts the controller. There is still a possibility of a pending interrupt
before controller is halted. If any event is pending with the controller
and SW trying to halt the controller then it resulting in undefined
behavior and leading to assertion of Host controller error(HCE).

Fix this by adding condition to check for interrupt pending during
controller halt. If any event is pending with the controller
then abort suspend.

Change-Id: I38fa6aeeeeccf130280c3af2927fb7f6693f755f
Signed-off-by: default avatarChandana Kishori Chiluveru <cchiluve@codeaurora.org>
parent 0c3a23a4
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -1877,8 +1877,12 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc)
		if (reg & PWR_EVNT_LPM_IN_L2_MASK)
			break;
	}
	if (!(reg & PWR_EVNT_LPM_IN_L2_MASK))

	if (!(reg & PWR_EVNT_LPM_IN_L2_MASK)) {
		dev_err(mdwc->dev, "could not transition HS PHY to L2\n");
		queue_delayed_work(mdwc->dwc3_wq, &mdwc->resume_work, 0);
		return -EBUSY;
	}

	/* Clear L2 event bit */
	dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_STAT_REG,
+4 −0
Original line number Diff line number Diff line
@@ -2647,6 +2647,10 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
	if (status == 0xffffffff)
		goto hw_died;

	if (status & STS_HCE) {
		xhci_warn(xhci, "WARNING: Host controller Error\n");
	}

	if (!(status & STS_EINT)) {
		spin_unlock(&xhci->lock);
		return IRQ_NONE;
+26 −0
Original line number Diff line number Diff line
@@ -946,6 +946,19 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
	/* Some chips from Fresco Logic need an extraordinary delay */
	delay *= (xhci->quirks & XHCI_SLOW_SUSPEND) ? 10 : 1;

	if ((readl(&xhci->op_regs->status) & STS_EINT) ||
			(readl(&xhci->op_regs->status) & STS_PORT)) {
		xhci_warn(xhci, "WARN: xHC EINT/PCD set status:%x\n",
			readl(&xhci->op_regs->status));
		set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
		set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
		/* step 4: set Run/Stop bit */
		command = readl(&xhci->op_regs->command);
		command |= CMD_RUN;
		writel(command, &xhci->op_regs->command);
		spin_unlock_irq(&xhci->lock);
		return -EBUSY;
	}
	if (xhci_handshake(xhci, &xhci->op_regs->status,
		      STS_HALT, STS_HALT, delay)) {
		xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");
@@ -954,6 +967,19 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
		spin_unlock_irq(&xhci->lock);
		return -ETIMEDOUT;
	}
	if ((readl(&xhci->op_regs->status) & STS_EINT) ||
			(readl(&xhci->op_regs->status) & STS_PORT)) {
		xhci_warn(xhci, "WARN: xHC EINT/PCD set status:%x\n",
			readl(&xhci->op_regs->status));
		set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
		set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
		/* step 4: set Run/Stop bit */
		command = readl(&xhci->op_regs->command);
		command |= CMD_RUN;
		writel(command, &xhci->op_regs->command);
		spin_unlock_irq(&xhci->lock);
		return -EBUSY;
	}
	xhci_clear_command_ring(xhci);

	/* step 3: save registers */