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

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

Merge "usb: dwc3: Issue core soft reset upon controller halt failure"

parents 2e8b7b69 66a6e729
Loading
Loading
Loading
Loading
+70 −21
Original line number Diff line number Diff line
@@ -811,39 +811,39 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)

	dwc3_stop_active_transfer(dep, true, false);

	if (dep->number == 1 && dwc->ep0state != EP0_SETUP_PHASE) {
		unsigned int dir;

		dbg_log_string("CTRLPEND", dwc->ep0state);
		dir = !!dwc->ep0_expect_in;
		if (dwc->ep0state == EP0_DATA_PHASE)
			dwc3_ep0_end_control_data(dwc, dwc->eps[dir]);
		else
			dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]);

		dwc->eps[0]->trb_enqueue = 0;
		dwc->eps[1]->trb_enqueue = 0;
	}

	/* - giveback all requests to gadget driver */
	while (!list_empty(&dep->started_list)) {
		req = next_request(&dep->started_list);

		if (req)
			dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
	}

	while (!list_empty(&dep->pending_list)) {
		req = next_request(&dep->pending_list);

		if (req)
			dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
	}

	while (!list_empty(&dep->cancelled_list)) {
		req = next_request(&dep->cancelled_list);

		if (req)
			dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
	}

	if (dep->number == 1 && dwc->ep0state != EP0_SETUP_PHASE) {
		unsigned int dir;

		dbg_log_string("CTRLPEND", dwc->ep0state);
		dir = !!dwc->ep0_expect_in;
		if (dwc->ep0state == EP0_DATA_PHASE)
			dwc3_ep0_end_control_data(dwc, dwc->eps[dir]);
		else
			dwc3_ep0_end_control_data(dwc, dwc->eps[!dir]);

		dwc->eps[0]->trb_enqueue = 0;
		dwc->eps[1]->trb_enqueue = 0;
	}

	dbg_log_string("DONE for %s(%d)", dep->name, dep->number);
}

@@ -1980,6 +1980,38 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc)
	}
}

/**
 * dwc3_device_core_soft_reset - Issues device core soft reset
 * @dwc: pointer to our context structure
 */
static int dwc3_device_core_soft_reset(struct dwc3 *dwc)
{
	u32             reg;
	int             retries = 10;

	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
	reg |= DWC3_DCTL_CSFTRST;
	dwc3_writel(dwc->regs, DWC3_DCTL, reg);

	do {
		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
		if (!(reg & DWC3_DCTL_CSFTRST))
			goto done;

		usleep_range(1000, 1100);
	} while (--retries);

	dev_err(dwc->dev, "%s timedout\n", __func__);

	return -ETIMEDOUT;

done:
	/* phy sync delay as per data book */
	msleep(50);

	return 0;
}

static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
{
	u32			reg, reg1;
@@ -2142,6 +2174,10 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)

	ret = dwc3_gadget_run_stop(dwc, is_on, false);
	spin_unlock_irqrestore(&dwc->lock, flags);
	if (!is_on && ret == -ETIMEDOUT) {
		dev_err(dwc->dev, "%s: Core soft reset...\n", __func__);
		dwc3_device_core_soft_reset(dwc);
	}
	enable_irq(dwc->irq);

	pm_runtime_mark_last_busy(dwc->dev);
@@ -2226,6 +2262,7 @@ static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active)
{
	struct dwc3 *dwc = gadget_to_dwc(_gadget);
	unsigned long flags;
	int ret = 0;

	if (dwc->dr_mode != USB_DR_MODE_OTG)
		return -EPERM;
@@ -2233,6 +2270,11 @@ static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active)
	is_active = !!is_active;

	dbg_event(0xFF, "VbusSess", is_active);

	disable_irq(dwc->irq);

	flush_work(&dwc->bh_work);

	spin_lock_irqsave(&dwc->lock, flags);

	/* Mark that the vbus was powered */
@@ -2248,9 +2290,9 @@ static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active)
			 * Both vbus was activated by otg and pullup was
			 * signaled by the gadget driver.
			 */
			dwc3_gadget_run_stop(dwc, 1, false);
			ret = dwc3_gadget_run_stop(dwc, 1, false);
		} else {
			dwc3_gadget_run_stop(dwc, 0, false);
			ret = dwc3_gadget_run_stop(dwc, 0, false);
		}
	}

@@ -2264,6 +2306,13 @@ static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active)
	}

	spin_unlock_irqrestore(&dwc->lock, flags);
	if (!is_active && ret == -ETIMEDOUT) {
		dev_err(dwc->dev, "%s: Core soft reset...\n", __func__);
		dwc3_device_core_soft_reset(dwc);
	}

	enable_irq(dwc->irq);

	return 0;
}