usb arc: discard stale transfers and audio work on bus reset

If RESET and IOC/SOF are reported together, the old interrupt order can refill audio or report completions from descriptors invalidated by the reset. Handle RESET first and return without dispatching those stale events. Disable SOF refill and stop the batch ring when resetting the controller.

The register-stub regression exercises simultaneous RESET, IOC and SOF and checks that no old completion or refill is dispatched.

Change-Id: Iac98df59aea30dfee155302f7ad31c6ba9902975
This commit is contained in:
Paul Sauro 2026-09-20 17:21:42 +02:00
parent d43cc0e829
commit 63978def70

View file

@ -553,6 +553,15 @@ void usb_drv_int(void)
unsigned int usbintr = REG_USBINTR; /* Only watch enabled ints */
unsigned int status = REG_USBSTS & usbintr;
/* Reset invalidates all old completions, including the audio ring.
* Do not dispatch a simultaneous SOF or IOC using stale descriptors. */
if (status & USBSTS_RESET) {
REG_USBSTS = status;
bus_reset();
usb_core_bus_reset();
return;
}
#if 0
if (status & USBSTS_INT) logf("int: usb ioc");
if (status & USBSTS_ERR) logf("int: usb err");
@ -579,13 +588,6 @@ void usb_drv_int(void)
logf("usb error int");
}
/* reset interrupt */
if (status & USBSTS_RESET) {
REG_USBSTS = USBSTS_RESET;
bus_reset();
usb_core_bus_reset(); /* tell mom */
}
/* port change */
if (status & USBSTS_PORT_CHANGE) {
REG_USBSTS = USBSTS_PORT_CHANGE;
@ -1155,6 +1157,9 @@ static void bus_reset(void)
int i;
logf("usb bus_reset");
REG_USBINTR &= ~USBINTR_SOF_EN;
batch_stopped = true;
REG_DEVICEADDR = 0;
pending_device_address = -1;
REG_ENDPTSETUPSTAT = REG_ENDPTSETUPSTAT;