[PATCH 2/2] usb: dwc3: gadget: Various fixes to trbs_left calculation

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

 



This patch fixes up some issues related to the trb_left calculation.

This calculation sometimes included the link trb slot in the trbs_left
and sometimes didn't.

In the case where the dequeue < enqueue, this number does not include
the link trb and should be used as-is. Otherwise it will include the
link_trb and should be decremented to reflect the actual amount of free
trb slots. The fixed calculation will be the proper amount of free TRB
slots left, taking into account whether a link TRB takes up one of the
slots.

When checking for full or empty where enqueue == dequeue, the pointer
may be 0. In that case previous TRB is the one before the link TRB. Use
that to check the HWO bit to see if we are full or empty.

In case DWC3_TRB_NUM is ever set lower than 256, mod trbs_left result by
DWC3_TRB_NUM.

In dwc3_prepare_trbs, if trbs_left is 0, do nothing and return early.

When an EP is enabled, initialized the TRB pool to clean up any stale
data. When the previous TRB was not properly cleaned up on disconnect,
the empty/full checking logic sometimes failed causing the EP to stop
processing requests.

Signed-off-by: John Youn <johnyoun@xxxxxxxxxxxx>
---
 drivers/usb/dwc3/gadget.c | 37 ++++++++++++++++++++++++++++++-------
 1 file changed, 30 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 3eaef22..a76634b 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -561,6 +561,12 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
 		if (usb_endpoint_xfer_control(desc))
 			goto out;
 
+		/* Initialize the TRB pool */
+		dep->trb_dequeue = 0;
+		dep->trb_enqueue = 0;
+		memset(dep->trb_pool, 0,
+		       sizeof(struct dwc3_trb) * DWC3_TRB_NUM);
+
 		/* Link TRB. The HWO bit is never reset */
 		trb_st_hw = &dep->trb_pool[0];
 
@@ -849,6 +855,8 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
 static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
 {
 	struct dwc3_trb		*tmp;
+	u8			tmp_index;
+	u8			trbs_left;
 
 	/*
 	 * If enqueue & dequeue are equal than it is either full or empty.
@@ -858,17 +866,29 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
 	 * more transfers in our ring.
 	 */
 	if (dep->trb_enqueue == dep->trb_dequeue) {
-		/* If we're full, enqueue/dequeue are > 0 */
-		if (dep->trb_enqueue) {
-			tmp = &dep->trb_pool[dep->trb_enqueue - 1];
-			if (tmp->ctrl & DWC3_TRB_CTRL_HWO)
-				return 0;
-		}
+		if (!dep->trb_enqueue)
+			/*
+			 * The TRB just before the zeroth one is the
+			 * one just before the LINK TRB.
+			 */
+			tmp_index = DWC3_TRB_NUM - 2;
+		else
+			tmp_index = dep->trb_enqueue - 1;
+
+		tmp = &dep->trb_pool[tmp_index];
+		if (tmp->ctrl & DWC3_TRB_CTRL_HWO)
+			return 0;
 
 		return DWC3_TRB_NUM - 1;
 	}
 
-	return dep->trb_dequeue - dep->trb_enqueue;
+	trbs_left = dep->trb_dequeue - dep->trb_enqueue;
+	trbs_left %= DWC3_TRB_NUM;
+
+	if (dep->trb_dequeue < dep->trb_enqueue)
+		trbs_left--;
+
+	return trbs_left;
 }
 
 static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
@@ -949,6 +969,9 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, int starting)
 
 	trbs_left = dwc3_calc_trbs_left(dep);
 
+	if (!trbs_left)
+		return;
+
 	list_for_each_entry_safe(req, n, &dep->pending_list, list) {
 		if (req->request.num_mapped_sgs > 0)
 			dwc3_prepare_one_trb_sg(dep, req, trbs_left--,
-- 
2.8.2

--
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