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: Pratham Pratap <prathampratap@codeaurora.org>
This commit is contained in:
Pratham Pratap 2020-09-21 19:51:01 +05:30
parent 66d2f99836
commit d8ed6a031f
2 changed files with 21 additions and 8 deletions
drivers/usb/dwc3

View file

@ -904,7 +904,12 @@ static void dwc3_stop_active_transfers_to_halt(struct dwc3 *dwc)
if (!(dep->flags & DWC3_EP_ENABLED))
continue;
dwc3_stop_active_transfer_noioc(dwc, dep->number, true);
/*
* If the transfers didn't stop due to some reason
* don't giveback the request to gadget driver.
*/
if (dwc3_stop_active_transfer_noioc(dwc, dep->number, true))
continue;
/* - giveback all requests to gadget driver */
while (!list_empty(&dep->started_list)) {
@ -2327,7 +2332,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
dwc->softconnect = is_on;
if ((dwc3_is_otg_or_drd(dwc) && !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.
@ -2391,8 +2396,15 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
ret = dwc3_gadget_run_stop_util(dwc);
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);
/*
* 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);
@ -3295,17 +3307,17 @@ void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
dep->name, dep->number, ret);
}
void dwc3_stop_active_transfer_noioc(struct dwc3 *dwc, u32 epnum, bool force)
int dwc3_stop_active_transfer_noioc(struct dwc3 *dwc, u32 epnum, bool force)
{
struct dwc3_ep *dep;
struct dwc3_gadget_ep_cmd_params params;
u32 cmd;
int ret;
int ret = 0;
dep = dwc->eps[epnum];
if (!dep->resource_index)
return;
return ret;
if (dep->endpoint.endless)
dwc3_notify_event(dwc, DWC3_CONTROLLER_NOTIFY_DISABLE_UPDXFER,
@ -3321,6 +3333,7 @@ void dwc3_stop_active_transfer_noioc(struct dwc3 *dwc, u32 epnum, bool force)
dbg_log_string("%s(%d): endxfer ret:%d)",
dep->name, dep->number, ret);
return ret;
}
static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)

View file

@ -126,7 +126,7 @@ 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 *dwc, u32 epnum, bool force);
void dwc3_stop_active_transfer_noioc(struct dwc3 *dwc, u32 epnum, bool force);
int dwc3_stop_active_transfer_noioc(struct dwc3 *dwc, u32 epnum, bool force);
void dwc3_ep_inc_enq(struct dwc3_ep *dep);
void dwc3_ep_inc_deq(struct dwc3_ep *dep);