usb: gadget: Don't giveback request if ep command times out

Currently driver is giving back requests to gadget even if
the active transfers are not stopped. This might lead the
controller to access the requests which are already unmapped.
This change adds a judgement for giving back the requests to
gadget based on ep command status. Also if ep command times out
and the controller doesn't stop correctly  then mark it as an
error event and restart the USB session.

Change-Id: If32cddddf0544140d5bdf68df9144702e00dc758
Signed-off-by: Udipto Goswami <ugoswami@codeaurora.org>
This commit is contained in:
Udipto Goswami 2020-11-18 14:49:21 +05:30
commit 61a365b701
2 changed files with 24 additions and 9 deletions

View file

@ -800,8 +800,7 @@ out:
static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
{
struct dwc3_request *req;
dwc3_stop_active_transfer(dep, true, false);
int ret = -EINVAL;
if (dep->number == 0 && dwc->ep0state != EP0_SETUP_PHASE) {
unsigned int dir;
@ -817,6 +816,13 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
dwc->eps[1]->trb_enqueue = 0;
}
ret = dwc3_stop_active_transfer(dep, true, false);
if (ret < 0) {
dbg_log_string("transfer not stopped for %s(%d), status:%d",
dep->name, dep->number, ret);
return;
}
if (dep->flags & DWC3_EP_END_TRANSFER_PENDING)
udelay(2000);
@ -2189,7 +2195,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
dwc->softconnect = is_on;
if (((dwc->dr_mode > USB_DR_MODE_HOST) && !dwc->vbus_active)
|| !dwc->gadget_driver) {
|| !dwc->gadget_driver || dwc->err_evt_seen) {
/*
* Need to wait for vbus_session(on) from otg driver or to
* the udc_start.
@ -2251,8 +2257,15 @@ 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__);
ret = dwc3_device_core_soft_reset(dwc);
/*
* If we fail to stop the controller then mark it as an error
* event since it can lead the controller to go into an unknown
* state.
*/
dbg_log_string("%s: error event seen\n", __func__);
dwc->err_evt_seen = true;
dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT, 0);
dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_CLEAR_DB, 0);
}
enable_irq(dwc->irq);
@ -2260,7 +2273,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
pm_runtime_put_autosuspend(dwc->dev);
dbg_event(0xFF, "Pullup put",
atomic_read(&dwc->dev->power.usage_count));
return ret;
return 0;
}
static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
@ -3152,7 +3165,7 @@ static void dwc3_reset_gadget(struct dwc3 *dwc)
}
}
void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt)
int dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt)
{
struct dwc3 *dwc = dep->dwc;
struct dwc3_gadget_ep_cmd_params params;
@ -3161,7 +3174,7 @@ void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt)
if (!(dep->flags & DWC3_EP_TRANSFER_STARTED) ||
(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
return;
return 0;
dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER,
dep->number);
@ -3215,6 +3228,8 @@ void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt)
if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A)
udelay(100);
return ret;
}
EXPORT_SYMBOL(dwc3_stop_active_transfer);

View file

@ -116,7 +116,7 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);
int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
gfp_t gfp_flags);
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt);
int dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force, bool interrupt);
static inline dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
struct dwc3_trb *trb)