[PATCH 3/3] usb: chipidea: udc: add errata for revision 2.40a

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

 



At chipidea revision 2.40a, there is a below errata:

9000531823	B2-Medium	Adding a dTD to a Primed Endpoint May Not Get Recognized

Title: Adding a dTD to a Primed Endpoint May Not Get Recognized
Impacted Configuration: All device mode configurations.
Description:
There is an issue with the add dTD tripwire semaphore (ATDTW bit in USBCMD register)
that can cause the controller to ignore a dTD that is added to a primed endpoint.
When this happens, the software can read the tripwire bit and the status bit at '1'
even though the endpoint is unprimed.
After executing a dTD, the device controller endpoint state machine executes a final
read of the dTD terminate bit to check if the application added a dTD to the linked
list at the last moment. This read is done in the finpkt_read_latest_next_td (44) state.
After the read is performed, if the terminate bit is still set, the state machine moves
to unprime the endpoint. The decision to unprime the endpoint is done in the
checkqh_decision (59) state, based on the value of the terminate bit.
Before reaching the checkqh_decision state, the state machine traverses the
writeqhtd_status (57), writeqh_status (56), and release_prime_mask (42) states.
As shown in the waveform, the ep_addtd_tripwire_clr signal is not set to clear
the tripwire bit in these states.

Workaround: The software must implement a periodic poll cycle, and check for each dTD
pending on execution (Active = 1), if the enpoint is primed. It can do this by reading
the corresponding bits in the ENDPTPRIME and ENDPTSTAT registers. If these bits are
read at 0, the software needs to re-prime the endpoint by writing 1 to the corresponding
bit in the ENDPTPRIME register. This can be done for every microframe, every frame or
with a larger interval, depending on the urgency of transfer execution for the application.

Cc: Sanchayan Maity <maitysanchayan@xxxxxxxxx>
Signed-off-by: Peter Chen <peter.chen@xxxxxxxxxxxxx>
---
 drivers/usb/chipidea/udc.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index c0754be..aefc1ae 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -201,7 +201,7 @@ static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl)
 	if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num)))
 		return -EAGAIN;
 
-	/* status shoult be tested according with manual but it doesn't work */
+	/* status should be tested according with manual but it doesn't work */
 	return 0;
 }
 
@@ -522,6 +522,19 @@ static void free_pending_td(struct ci_hw_ep *hwep)
 	kfree(pending);
 }
 
+static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep)
+{
+	int n = hw_ep_bit(hwep->num, hwep->dir);
+
+	/* Only do re-prime when both ENDPTPRIME bit and ENDPTSTAT bit are 0 */
+	if (hw_read(ci, OP_ENDPTPRIME, BIT(n)) ||
+			hw_read(ci, OP_ENDPTSTAT, BIT(n)))
+		return 0;
+
+	return hw_ep_prime(ci, hwep->num, hwep->dir,
+			   hwep->type == USB_ENDPOINT_XFER_CONTROL);
+}
+
 /**
  * _hardware_dequeue: handles a request at hardware level
  * @gadget: gadget
@@ -535,6 +548,7 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
 	struct td_node *node, *tmpnode;
 	unsigned remaining_length;
 	unsigned actual = hwreq->req.length;
+	struct ci_hdrc *ci = hwep->ci;
 
 	if (hwreq->req.status != -EALREADY)
 		return -EINVAL;
@@ -544,6 +558,8 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
 	list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
 		tmptoken = le32_to_cpu(node->ptr->token);
 		if ((TD_STATUS_ACTIVE & tmptoken) != 0) {
+			if (ci->rev == CI_REVISION_24)
+				reprime_dtd(ci, hwep);
 			hwreq->req.status = -EALREADY;
 			return -EBUSY;
 		}
-- 
1.9.1

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