diff options
Diffstat (limited to 'drivers/usb/dwc3/gadget.c')
| -rw-r--r-- | drivers/usb/dwc3/gadget.c | 31 | 
1 files changed, 30 insertions, 1 deletions
| diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index ab725d2262d6..0b9c2493844a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3274,6 +3274,7 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,  		const struct dwc3_event_depevt *event,  		struct dwc3_request *req, int status)  { +	int request_status;  	int ret;  	if (req->request.num_mapped_sgs) @@ -3294,7 +3295,35 @@ static int dwc3_gadget_ep_cleanup_completed_request(struct dwc3_ep *dep,  		req->needs_extra_trb = false;  	} -	dwc3_gadget_giveback(dep, req, status); +	/* +	 * The event status only reflects the status of the TRB with IOC set. +	 * For the requests that don't set interrupt on completion, the driver +	 * needs to check and return the status of the completed TRBs associated +	 * with the request. Use the status of the last TRB of the request. +	 */ +	if (req->request.no_interrupt) { +		struct dwc3_trb *trb; + +		trb = dwc3_ep_prev_trb(dep, dep->trb_dequeue); +		switch (DWC3_TRB_SIZE_TRBSTS(trb->size)) { +		case DWC3_TRBSTS_MISSED_ISOC: +			/* Isoc endpoint only */ +			request_status = -EXDEV; +			break; +		case DWC3_TRB_STS_XFER_IN_PROG: +			/* Applicable when End Transfer with ForceRM=0 */ +		case DWC3_TRBSTS_SETUP_PENDING: +			/* Control endpoint only */ +		case DWC3_TRBSTS_OK: +		default: +			request_status = 0; +			break; +		} +	} else { +		request_status = status; +	} + +	dwc3_gadget_giveback(dep, req, request_status);  out:  	return ret; |