U-boot didn’t seem to like some endpoint halting on the ortholinear keyboard we’re working on - when any more than one keystroke was made (even on non-emitting keys), it would error out and reset with these error messages:
WARN halted endpoint, queueing URB anyway.
Unexpected XHCI event TRB, skipping... (3aef7cf0 00000000 13000000 03008400)
BUG at drivers/usb/host/xhci-ring.c:498/abort_td()!
BUG!
resetting ...
When I messed up my boot.scr while moving things to my nvme, this made it a little difficult to debug what was going on
Thankfully, implementing this patch (with the printf removed) allows for full use of the keyboard, just like the OG one.
If anyone has any insight into the actual issue with the endpoints, maybe that’s something we could try to address in QMK - I do have things like the virtual serial interface, mouse keys, and console enabled, all of which add additional endpoints.
Here’s the patch I used that’s current with the reform’s u-boot fork - I’d create a merge request, but it looks like my account needs to be approved still
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index b2cfd948f8..bd353aef3c 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -473,6 +473,35 @@ 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).
+ * from https://github.com/agners/operating-system/blob/c3288801d7ff35c12d33d0e883dac246c4fc8a5a/buildroot-external/board/raspberrypi/patches/uboot/0005-usb-xhci-reset-endpoint-on-USB-stall.patch
+ */
+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;
+
+ // bit hard to type with this notification
+ //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
@@ -918,6 +947,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)
For anyone who is trying this for the first time (like me!), these commands (only step 2) for updating the flash.bin worked well.