summaryrefslogtreecommitdiffstats
path: root/pkgs/misc/uboot
diff options
context:
space:
mode:
authorBernardo Meurer <bernardo@meurer.org>2022-04-26 15:56:41 -0700
committerBernardo Meurer <bernardo@meurer.org>2022-04-26 19:05:25 -0700
commitcff95d119343fe2808516a0f8f86c8ba0963b29c (patch)
tree2b01aa29887da4177a1ccd486e809868d46e7f6a /pkgs/misc/uboot
parent11c1152e0f4f35e22249bc8d02e1d30e29b53032 (diff)
ubootRaspberryPi4_64bit: add patch for USB stall with non-MSD USB devices
Diffstat (limited to 'pkgs/misc/uboot')
-rw-r--r--pkgs/misc/uboot/default.nix1
-rw-r--r--pkgs/misc/uboot/rpi-cm4/0002-usb-xhci-reset-endpoint-on-USB-stall.patch87
2 files changed, 88 insertions, 0 deletions
diff --git a/pkgs/misc/uboot/default.nix b/pkgs/misc/uboot/default.nix
index 92b03e7d863b..abcf0e027617 100644
--- a/pkgs/misc/uboot/default.nix
+++ b/pkgs/misc/uboot/default.nix
@@ -425,6 +425,7 @@ in {
CONFIG_USB_XHCI_BRCM=y
'';
extraPatches = [
+ ./rpi-cm4/0002-usb-xhci-reset-endpoint-on-USB-stall.patch
./rpi-cm4/0003-rpi-add-NVMe-to-boot-order.patch
./rpi-cm4/0004-Revert-nvme-Correct-the-prps-per-page-calculation-me.patch
./rpi-cm4/0005-usb-xhci-brcm-Make-driver-compatible-with-downstream.patch
diff --git a/pkgs/misc/uboot/rpi-cm4/0002-usb-xhci-reset-endpoint-on-USB-stall.patch b/pkgs/misc/uboot/rpi-cm4/0002-usb-xhci-reset-endpoint-on-USB-stall.patch
new file mode 100644
index 000000000000..52124de7da14
--- /dev/null
+++ b/pkgs/misc/uboot/rpi-cm4/0002-usb-xhci-reset-endpoint-on-USB-stall.patch
@@ -0,0 +1,87 @@
+From c942eb452c1c31fe6259178b6e9fea5456d7fb9c Mon Sep 17 00:00:00 2001
+Message-Id: <c942eb452c1c31fe6259178b6e9fea5456d7fb9c.1645627172.git.stefan@agner.ch>
+In-Reply-To: <24b77460dbfa2497ceb7a1611bf28b6eb88a1d74.1645627172.git.stefan@agner.ch>
+References: <24b77460dbfa2497ceb7a1611bf28b6eb88a1d74.1645627172.git.stefan@agner.ch>
+From: Stefan Agner <stefan@agner.ch>
+Date: Mon, 27 Sep 2021 12:28:04 +0200
+Subject: [PATCH 2/5] usb: xhci: reset endpoint on USB stall
+
+There are devices which cause a USB stall when trying to read strings.
+Specifically Arduino Mega R3 stalls when trying to read the product
+string.
+
+The stall currently remains unhandled, and subsequent retries submit new
+transfers on a stopped endpoint which ultimately cause a crash in
+abort_td():
+WARN halted endpoint, queueing URB anyway.
+XHCI control transfer timed out, aborting...
+Unexpected XHCI event TRB, skipping... (3affe040 00000000 13000000 02008401)
+BUG at drivers/usb/host/xhci-ring.c:505/abort_td()!
+BUG!
+resetting ...
+
+Linux seems to be able to recover from the stall by issuing a
+TRB_RESET_EP command.
+
+Introduce reset_ep() which issues a TRB_RESET_EP followed by setting the
+transfer ring dequeue pointer via TRB_SET_DEQ. This allows to properly
+recover from a USB stall error and continue communicating with the USB
+device.
+
+Signed-off-by: Stefan Agner <stefan@agner.ch>
+---
+ drivers/usb/host/xhci-ring.c | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
+index 35bd5cd29e..430823cb9d 100644
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -481,6 +481,33 @@ union xhci_trb *xhci_wait_for_event(struct xhci_ctrl *ctrl, trb_type expected)
+ BUG();
+ }
+
++/*
++ * Issue reset endpoint command for an endpoint. This is required to recover
++ * a halted endpoint (e.g. due to a stall error).
++ */
++static void reset_ep(struct usb_device *udev, int ep_index)
++{
++ struct xhci_ctrl *ctrl = xhci_get_ctrl(udev);
++ struct xhci_ring *ring = ctrl->devs[udev->slot_id]->eps[ep_index].ring;
++ union xhci_trb *event;
++ u32 field;
++
++ printf("Resetting EP...\n");
++ xhci_queue_command(ctrl, NULL, udev->slot_id, ep_index, TRB_RESET_EP);
++ event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
++ field = le32_to_cpu(event->trans_event.flags);
++ BUG_ON(TRB_TO_SLOT_ID(field) != udev->slot_id);
++ xhci_acknowledge_event(ctrl);
++
++ xhci_queue_command(ctrl, (void *)((uintptr_t)ring->enqueue |
++ ring->cycle_state), udev->slot_id, ep_index, TRB_SET_DEQ);
++ event = xhci_wait_for_event(ctrl, TRB_COMPLETION);
++ BUG_ON(TRB_TO_SLOT_ID(le32_to_cpu(event->event_cmd.flags))
++ != udev->slot_id || GET_COMP_CODE(le32_to_cpu(
++ event->event_cmd.status)) != COMP_SUCCESS);
++ xhci_acknowledge_event(ctrl);
++}
++
+ /*
+ * Stops transfer processing for an endpoint and throws away all unprocessed
+ * TRBs by setting the xHC's dequeue pointer to our enqueue pointer. The next
+@@ -928,6 +955,10 @@ int xhci_ctrl_tx(struct usb_device *udev, unsigned long pipe,
+
+ record_transfer_result(udev, event, length);
+ xhci_acknowledge_event(ctrl);
++ if (udev->status == USB_ST_STALLED) {
++ reset_ep(udev, ep_index);
++ return -EPIPE;
++ }
+
+ /* Invalidate buffer to make it available to usb-core */
+ if (length > 0)
+--
+2.35.1
+