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

From b887f8bb547b56f6a0c0c7102a9d232df6f174c6 Mon Sep 17 00:00:00 2001
From: cidlik zubastikiko@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)
participants (1)
-
Роман Кузнецов