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

Commit a937192b authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: dwc3: Fix out of bound memory access for event buffer"

parents e4897e8b 3752d945
Loading
Loading
Loading
Loading
+30 −8
Original line number Diff line number Diff line
@@ -2098,24 +2098,27 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
		 */
		dwc3_stop_active_transfers(dwc);

		reg &= ~DWC3_DCTL_RUN_STOP;

		if (dwc->has_hibernation && !suspend)
			reg &= ~DWC3_DCTL_KEEP_CONNECT;
	}

	dwc3_writel(dwc->regs, DWC3_DCTL, reg);

	/* Controller is not halted until the events are acknowledged */
	if (!is_on) {
		/*
		 * Clear out any pending events (i.e. End Transfer Command
		 * Complete) before clearing run/stop
		 * Complete).
		 */
		reg1 = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
		reg1 &= DWC3_GEVNTCOUNT_MASK;
		dbg_log_string("remaining EVNTCOUNT(0)=%d", reg1);
		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg1);
		dwc3_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEAR, 0);

		reg &= ~DWC3_DCTL_RUN_STOP;

		if (dwc->has_hibernation && !suspend)
			reg &= ~DWC3_DCTL_KEEP_CONNECT;
	}

	dwc3_writel(dwc->regs, DWC3_DCTL, reg);

	do {
		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
		reg &= DWC3_DSTS_DEVCTRLHLT;
@@ -3749,6 +3752,12 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
	if (dwc->err_evt_seen)
		return IRQ_HANDLED;

	/* Controller is being halted, ignore the interrupts */
	if (!dwc->pullups_connected) {
		dbg_event(0xFF, "NO_PULLUP", 0);
		return IRQ_HANDLED;
	}

	/*
	 * With PCIe legacy interrupt, test shows that top-half irq handler can
	 * be called again after HW interrupt deassertion. Check if bottom-half
@@ -3763,6 +3772,19 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
	if (!count)
		return IRQ_NONE;

	if (count > evt->length) {
		dbg_event(0xFF, "HUGE_EVCNT", count);
		/*
		 * If writes from dwc3_interrupt and run_stop(0) races
		 * with each other, the count can result in a very large
		 * value.In that case setting the evt->lpos here
		 * is a no-op. The value will be reset as part of run_stop(1).
		 */
		evt->lpos = (evt->lpos + count) % DWC3_EVENT_BUFFERS_SIZE;
		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
		return IRQ_HANDLED;
	}

	evt->count = count;
	evt->flags |= DWC3_EVENT_PENDING;