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

This commit is contained in:
qctecmdr 2019-12-10 18:39:05 -08:00 • committed by Gerrit - the friendly Code Review server
commit e64d784137

View file

@ -811,25 +811,6 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
dwc3_stop_active_transfer(dep, true, false);
/* - giveback all requests to gadget driver */
while (!list_empty(&dep->started_list)) {
req = next_request(&dep->started_list);
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
}
while (!list_empty(&dep->pending_list)) {
req = next_request(&dep->pending_list);
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
}
while (!list_empty(&dep->cancelled_list)) {
req = next_request(&dep->cancelled_list);
dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
}
if (dep->number == 1 && dwc->ep0state != EP0_SETUP_PHASE) {
unsigned int dir;
@ -844,6 +825,25 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
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);
}
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;
}