[PATCH] usb: dwc3: Fix assignment of EP transfer resources

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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, &params);
 	}
 
@@ -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



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux