diff mbox series

xhci: Add soft retry mechanism for control transaction

Message ID CAL0n43U23ZDvBQ+WVT0o=MSmJoYXNc1-Ztduh82mo9MAuG9GpQ@mail.gmail.com
State New
Delegated to: Marek Vasut
Headers show
Series xhci: Add soft retry mechanism for control transaction | expand

Commit Message

Роман Кузнецов June 18, 2023, 9:44 a.m. UTC
Hello!

I have a problem with using the USB stick Transcend Jetflash 350. After
entering the command "usb reset" were getting three different results:

1. [OK] USB stick was found.
2. [ERROR] Message:

USB XHCI 1.10
scanning bus dwc3@10000000 for devices... usb_new_device: Cannot read
    configuration, skipping device 8564:1000

3. [ERROR] Message:

USB XHCI 1.10
scanning bus dwc3@10000000 for devices... WARN halted endpoint,
    queueing URB anyway.
Unexpected XHCI event TRB, skipping... (9fb69170 00000008
    13000000 01008401)
BUG at drivers/usb/host/xhci-ring.c:530/abort_td()!
BUG!

I tried to dump a USB transaction via Wireshark + USBPcap and noticed
that several transactions were errors. After reading the docs
"eXtensible Host Controller Interface for Universal Serial Bus" was
realized the retry mechanism. It solved my problem.

Best regards,
Mark Smith
---

From b887f8bb547b56f6a0c0c7102a9d232df6f174c6 Mon Sep 17 00:00:00 2001
From: Mark Smith <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

Signed-off-by: Mark Smith <zubastikiko@gmail.com>
---
 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 mbox series

Patch

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)