The assignement of EP transfer resources was not handled properly in the dwc3 driver. Commit aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") previously fixed one aspect of this where resources may be exhausted with multiple calls to SET_INTERFACE. However, it introduced an issue where composite devices with multiple interfaces can be assigned the same transfer resources for different endpoints. This patch solves both issues. The assigning of transfer resource should go as follows: Each hardware endpoint requires a transfer resource before it can perform any USB transfer. The transfer resources are allocated using two commands: DEPSTARTCFG and DEPXFERCFG. In the controller, there is a transfer resource index that is set by the DEPSTARTCFG command. The DEPXFERCFG command assigns the resource to an endpoint and increments the transfer resource index. Upon startup of the driver, the transfer resource index should be set to 0 by issuing DEPSTARTCFG(0). EP0-out and EP0-in are then assigned a resource by DEPXFERCFG. They are assigned resource indexes 0 and 1. Every time a SET_CONFIGURATION usb request occurs the DEPSTARTCFG(2) command should be issued to reset the index to 2. Transfer resources 0 and 1 remain assigned to EP0-out and EP0-in. Then for every endpoint in the configuration (endpoints that will be enabled by the upper layer) call DEPXFERCFG to assign the next resource. On SET_INTERFACE, the same or different endpoints may be enabled. If the endpoint already has an assigned transfer resource, don't assign a new one. Fixes: aebda6187181 ("usb: dwc3: Reset the transfer resource index on SET_INTERFACE") Reported-by: Ravi Babu <ravibabu@xxxxxx> Signed-off-by: John Youn <johnyoun@xxxxxxxxxxxx> --- Hi Ravi, Here is a patch that should solve your issue. Can you review and test it out? I have tested with multiple SET_INTERFACE for a single interface. Thanks, John drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/ep0.c | 4 ---- drivers/usb/dwc3/gadget.c | 36 +++++++++++++++++++++++++++++++++--- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 2913068..7d5d3a2 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -453,6 +453,8 @@ struct dwc3_event_buffer { * @flags: endpoint flags (wedged, stalled, ...) * @number: endpoint number (1 - 15) * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK + * @resource_assigned: indicates that a transfer resource is assigned + * to this endpoint * @resource_index: Resource transfer index * @interval: the interval on which the ISOC transfer is started * @name: a human readable name e.g. ep1out-bulk @@ -485,6 +487,7 @@ struct dwc3_ep { u8 number; u8 type; + unsigned resource_assigned:1; u8 resource_index; u32 interval; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3a9354a..878b40e 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -737,10 +737,6 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_ISOCH_DELAY"); ret = dwc3_ep0_set_isoch_delay(dwc, ctrl); break; - case USB_REQ_SET_INTERFACE: - dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_INTERFACE"); - dwc->start_config_issued = false; - /* Fall through */ default: dwc3_trace(trace_dwc3_ep0, "Forwarding to gadget driver"); ret = dwc3_ep0_delegate_req(dwc, ctrl); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 7d1dd82..1aeea8f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -385,6 +385,30 @@ static void dwc3_free_trb_pool(struct dwc3_ep *dep) dep->trb_pool_dma = 0; } +static void dwc3_gadget_reset_xfer_resource_for_ep(struct dwc3 *dwc, + int num, + int direction) +{ + struct dwc3_ep *dep; + int idx; + + idx = (num << 1) | direction; + dep = dwc->eps[idx]; + dep->resource_assigned = 0; +} + +static void dwc3_gadget_reset_xfer_resources(struct dwc3 *dwc, bool do_ep0) +{ + int i; + int first_ep = do_ep0 ? 0 : 1; + + for (i = first_ep; i < dwc->num_out_eps; i++) + dwc3_gadget_reset_xfer_resource_for_ep(dwc, i, 0); + + for (i = first_ep; i < dwc->num_in_eps; i++) + dwc3_gadget_reset_xfer_resource_for_ep(dwc, i, 1); +} + static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_gadget_ep_cmd_params params; @@ -402,6 +426,8 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep) cmd |= DWC3_DEPCMD_PARAM(2); } + dwc3_gadget_reset_xfer_resources(dwc, !dep->number); + return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, ¶ms); } @@ -516,9 +542,13 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, struct dwc3_trb *trb_st_hw; struct dwc3_trb *trb_link; - ret = dwc3_gadget_set_xfer_resource(dwc, dep); - if (ret) - return ret; + if (!dep->resource_assigned) { + ret = dwc3_gadget_set_xfer_resource(dwc, dep); + if (ret) + return ret; + + dep->resource_assigned = 1; + } dep->endpoint.desc = desc; dep->comp_desc = comp_desc; -- 2.6.3 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html