[PATCH] xhci: Add soft retry mechanism for control transaction

Роман Кузнецов zubastikiko at gmail.com
Thu Jun 1 22:39:19 CEST 2023


>From b887f8bb547b56f6a0c0c7102a9d232df6f174c6 Mon Sep 17 00:00:00 2001
From: cidlik <zubastikiko at gmail.com>
Date: Thu, 1 Jun 2023 23:20:03 +0300
Subject: [PATCH] xhci: Add soft retry mechanism for control transaction

A Soft Retry may effectively be used to recover from a USB Transaction
Error that was due to a temporary error condition.

Software shall limit the number of unsuccessful Soft Retry attempts to
prevent an infinite loop.

For more details on Soft retry see xhci specs  4.6.8.1
---
 drivers/usb/host/xhci-ring.c |  7 +++++++
 drivers/usb/host/xhci.c      | 12 +++++++++++-
 include/usb/xhci.h           |  2 ++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index c8260cbdf9..10f5fe4d06 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -580,6 +580,9 @@ static void record_transfer_result(struct usb_device *udev,
    case COMP_SHORT_TX:
        udev->status = 0;
        break;
+   case COMP_TX_ERR:
+       udev->status = USB_ST_CRC_ERR;
+       break;
    case COMP_STALL:
        udev->status = USB_ST_STALLED;
        break;
@@ -979,6 +982,10 @@ int xhci_ctrl_tx(struct usb_device *udev,
unsigned long pipe,
        reset_ep(udev, ep_index);
        return -EPIPE;
    }
+   if (udev->status == USB_ST_CRC_ERR ) {
+       reset_ep(udev, ep_index);
+       return -EAGAIN;
+   }

    /* Invalidate buffer to make it available to usb-core */
    if (length > 0) {
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 9e33c5d855..efb9fc2950 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1156,6 +1156,7 @@ static int _xhci_submit_control_msg(struct
usb_device *udev, unsigned long pipe,
 {
    struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
    int ret = 0;
+   int soft_reset_attempt = SOFT_RESET_ATTEMPTS;

    if (usb_pipetype(pipe) != PIPE_CONTROL) {
        printf("non-control pipe (type=%lu)", usb_pipetype(pipe));
@@ -1178,7 +1179,16 @@ static int _xhci_submit_control_msg(struct
usb_device *udev, unsigned long pipe,
        }
    }

-   return xhci_ctrl_tx(udev, pipe, setup, length, buffer);
+   while(soft_reset_attempt > 0)
+   {
+       ret = xhci_ctrl_tx(udev, pipe, setup, length, buffer);
+       if (ret == -EAGAIN)
+           soft_reset_attempt--;
+       else
+           return ret;
+   }
+   printf("control transfer is unsuccessful after %d attempts\n",
SOFT_RESET_ATTEMPTS);
+   return ret;
 }

 static int xhci_lowlevel_init(struct xhci_ctrl *ctrl)
diff --git a/include/usb/xhci.h b/include/usb/xhci.h
index 4a4ac10229..9cc3bfaf3c 100644
--- a/include/usb/xhci.h
+++ b/include/usb/xhci.h
@@ -33,6 +33,8 @@
 /* Section 5.3.3 - MaxPorts */
 #define MAX_HC_PORTS            255

+#define SOFT_RESET_ATTEMPTS    3
+
 /* Up to 16 ms to halt an HC */
 #define XHCI_MAX_HALT_USEC (16*1000)

-- 
2.38.0.windows.1


More information about the U-Boot mailing list