[RFT PATCH v1 5/5] usb: Handle QT_TOKEN_STATUS_XACTERR error when sending data

Lukasz Majewski
2020-03-22T13:00:31Z

This code adds check if QT_TOKEN_STATUS_XACTERR error occurred. When it is
detected the token is reconfigured and transmission is retried.

This code is the port to newest U-Boot of the fix from - "rayvt" (from [1]).

Links:
[1] - https://forum.doozan.com/read.php?3,35295,35295#msg-35295
[2] - https://www.dropbox.com/s/nrkrd1no63viuu8/uboot-bodhi-2016.05-timeoutTD.patch?dl=0

Signed-off-by: Lukasz Majewski <lukma@denx.de>
[Unfortunately, the original patch [2] did not contain S-o-B from the original
author - "rayvt"]
---

drivers/usb/host/ehci-hcd.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 0a77111f80..45eda7ad24 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -315,6 +315,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
int timeout;
int ret = 0;
struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);
+ int trynum;

debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
buffer, length, req);
@@ -560,6 +561,10 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
ehci_writel(&ctrl->hcor->or_usbsts, (usbsts & 0x3f));

/* Enable async. schedule. */
+ trynum = 1; /* No more than 2 tries, in case of XACTERR. */
+retry_xacterr:;
+ vtd = &qtd[qtd_counter - 1];
+
cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
cmd |= CMD_ASE;
ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
@@ -573,8 +578,8 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,

/* Wait for TDs to be processed. */
ts = get_timer(0);
- vtd = &qtd[qtd_counter - 1];
timeout = USB_TIMEOUT_MS(pipe);
+ timeout += dev->extra_timeout;
do {
/* Invalidate dcache */
invalidate_dcache_range((unsigned long)&ctrl->qh_list,
@@ -589,6 +594,7 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
break;
WATCHDOG_RESET();
} while (get_timer(ts) < timeout);
+ debug("took %4lu ms of %4d\n", get_timer(ts), timeout);

/*
* Invalidate the memory area occupied by buffer
@@ -622,6 +628,25 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
token = hc32_to_cpu(qh->qh_overlay.qt_token);
if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)) {
debug("TOKEN=%#x\n", token);
+ if (token & QT_TOKEN_STATUS_XACTERR) {
+ if (--trynum >= 0) {
+ /*
+ * It is necessary to do this, otherwise the
+ * disk is clagged.
+ */
+ debug("reset the TD and redo, because of XACTERR\n");
+ token &= ~QT_TOKEN_STATUS_HALTED;
+ token |= QT_TOKEN_STATUS_ACTIVE |
+ QT_TOKEN_CERR(2);
+ vtd->qt_token = cpu_to_hc32(token);
+ qh->qh_overlay.qt_token = cpu_to_hc32(token);
+ goto retry_xacterr;
+ }
+ dev->status = USB_ST_XACTERR;
+ dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);
+ goto fail;
+ }
+
switch (QT_TOKEN_GET_STATUS(token) &
~(QT_TOKEN_STATUS_SPLITXSTATE | QT_TOKEN_STATUS_PERR)) {
case 0:
--
2.20.1