Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.5:Update
u-boot.25329
0037-usb-xhci-reset-endpoint-on-USB-stal.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0037-usb-xhci-reset-endpoint-on-USB-stal.patch of Package u-boot.25329
From 47d960b7040414613bf8432907cb7a85a500ca30 Mon Sep 17 00:00:00 2001 From: Stefan Agner <stefan@agner.ch> Date: Mon, 27 Sep 2021 14:42:58 +0200 Subject: [PATCH] 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> (cherry picked from commit d5daa02d8d9e7c403a3339db1966e8413e64e408) Signed-off-by: Matthias Brugger <mbrugger@suse.com> --- 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 6b31ad4398..b6ed3227ce 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(); } +/* + * Send reset endpoint command for given endpoint. This recovers from 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 %d...\n", ep_index); + 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 @@ -931,6 +958,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)
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor