Hi Stuart,
On 2025-11-25 22:29, Stuart Henderson wrote:
iirc there was something about disabling USB 3 or XHCI handoff
or legacy USB support on these...
Thanks for pointing to these options. I have played with most of them
and unfortunately I didn't have a luck.
Maybe only one time the `uhub3` was properly detected during BMC reset
but that was it.
I have tested a few Linux distros (live-usb-booting) and it seems the
Linux kernel handles the BMC reset
(not sure if it does some sort of workaround or because of its different
"nature").
I spend some time and managed to build a kernel with the following "bad
and ugly" patch and the keyboard
works after a BMC reset. This was just a proof-of-concept and I'm not an
USB-stack expert - but it was fun after all :)
Index: dev/usb/xhci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/xhci.c,v
diff -u -p -r1.136 xhci.c
--- dev/usb/xhci.c 1 Mar 2025 14:43:03 -0000 1.136
+++ dev/usb/xhci.c 25 Nov 2025 21:59:35 -0000
@@ -54,6 +54,42 @@ int xhcidebug = 3;
#define TRBOFF(r, trb) ((char *)(trb) - (char *)((r)->trbs))
#define DEQPTR(r) ((r).dma.paddr + (sizeof(struct xhci_trb) *
(r).index))
+#define XHCI_BMC_PORT 3
+#define XHCI_BMC_DELAY_MS 300
+
+void
+xhci_rh_task(void *arg)
+{
+ struct xhci_softc *sc = arg;
+ struct usbd_xfer *xfer;
+ int s;
+
+ /* Check if the BMC Delay flag was set by the interrupt handler */
+ if (sc->sc_flags & XHCI_BMC_DELAY_ACTIVE) {
+ printf("%s: BMC detected on Port %d - waiting %dms for
stability...\n",
+ DEVNAME(sc), XHCI_BMC_PORT, XHCI_BMC_DELAY_MS);
+
+ usb_delay_ms(&sc->sc_bus, XHCI_BMC_DELAY_MS);
+
+ /* Clear the flag */
+ s = splusb();
+ sc->sc_flags &= ~XHCI_BMC_DELAY_ACTIVE;
+ splx(s);
+ }
+
+ /* Now notify the USB stack that the port status has changed */
+ s = splusb();
+ xfer = sc->sc_intrxfer;
+
+ if (xfer != NULL) {
+ /* The buffer 'p' was populated by xhci_event_port_change */
+ xfer->actlen = xfer->length;
+ xfer->status = USBD_NORMAL_COMPLETION;
+ usb_transfer_complete(xfer);
+ }
+ splx(s);
+}
+
struct pool *xhcixfer;
struct xhci_pipe {
@@ -295,6 +331,9 @@ xhci_init(struct xhci_softc *sc)
uint32_t hcr;
int npage, error;
+ /* Initialize the generic Root Hub task */
+ usb_init_task(&sc->sc_rh_task, xhci_rh_task, sc,
USB_TASK_TYPE_GENERIC);
+
sc->sc_bus.usbrev = USBREV_3_0;
sc->sc_bus.methods = &xhci_bus_methods;
sc->sc_bus.pipe_size = sizeof(struct xhci_pipe);
@@ -1182,6 +1221,7 @@ xhci_event_port_change(struct xhci_softc
struct usbd_xfer *xfer = sc->sc_intrxfer;
uint32_t port = XHCI_TRB_PORTID(paddr);
uint8_t *p;
+ uint32_t portsc;
if (XHCI_TRB_GET_CODE(status) != XHCI_CODE_SUCCESS) {
DPRINTF(("%s: failed port status event\n", DEVNAME(sc)));
@@ -1193,14 +1233,19 @@ xhci_event_port_change(struct xhci_softc
p = KERNADDR(&xfer->dmabuf, 0);
memset(p, 0, xfer->length);
-
p[port/8] |= 1 << (port%8);
+
DPRINTF(("%s: port=%d change=0x%02x\n", DEVNAME(sc), port, *p));
- xfer->actlen = xfer->length;
- xfer->status = USBD_NORMAL_COMPLETION;
+ /* Check for BMC Workaround Condition */
+ portsc = XOREAD4(sc, XHCI_PORTSC(port));
+
+ /* If it's the BMC port connecting, flag it for delay */
+ if (port == XHCI_BMC_PORT && (portsc & XHCI_PS_CSC) && (portsc &
XHCI_PS_CCS)) {
+ sc->sc_flags |= XHCI_BMC_DELAY_ACTIVE;
+ }
- usb_transfer_complete(xfer);
+ usb_add_task(xfer->device, &sc->sc_rh_task);
}
void
Index: dev/usb/xhcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/xhcivar.h,v
diff -u -p -r1.17 xhcivar.h
--- dev/usb/xhcivar.h 1 Feb 2025 22:46:34 -0000 1.17
+++ dev/usb/xhcivar.h 25 Nov 2025 21:59:35 -0000
@@ -124,6 +124,8 @@ struct xhci_softc {
int sc_flags;
#define XHCI_NOCSS 0x01
+#define XHCI_BMC_DELAY_ACTIVE 0x02
+ struct usb_task sc_rh_task;
};
int xhci_init(struct xhci_softc *);