drivers: udc_dwc2: handle interrupt IEPINT before the RXFLVL

During a control read transfer host is able to start status stage as
soon as it receives last data packet. The time between last data packet
and status stage can be approximately 1 us at High-Speed and 8 us at
Full-Speed (exact timing depends on host but it is mostly constrained by
bus turnaround time).

With sufficient interrupt latency it is therefore possible that both
IEPINT (raised at end of Data Stage) and RXFLVL (raised at Status Stage)
would be set when dwc2 interrupt handler reads GINTSTS register. When
device is operating at High-Speed, the latency introduced by UART logger
backend is enough to trigger this condition. If the RXFLVL is handled
before IEPINT the stack will trigger "Cannot determine the next stage"
error.

Handle IEPINT before RXFLVL to make the handler immune to increased
interrupt latencies.

Co-authored-by: Tomasz Moń <tomasz.mon@nordicsemi.no>
Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
This commit is contained in:
Johann Fischer 2024-05-08 15:28:55 +02:00 committed by Fabio Baltieri
commit b501278237

View file

@ -888,16 +888,16 @@ static void udc_dwc2_isr_handler(const struct device *dev)
udc_submit_event(dev, UDC_EVT_RESUME, 0); udc_submit_event(dev, UDC_EVT_RESUME, 0);
} }
if (int_status & USB_DWC2_GINTSTS_RXFLVL) {
/* Handle RxFIFO Non-Empty interrupt */
dwc2_handle_rxflvl(dev);
}
if (int_status & USB_DWC2_GINTSTS_IEPINT) { if (int_status & USB_DWC2_GINTSTS_IEPINT) {
/* Handle IN Endpoints interrupt */ /* Handle IN Endpoints interrupt */
dwc2_handle_iepint(dev); dwc2_handle_iepint(dev);
} }
if (int_status & USB_DWC2_GINTSTS_RXFLVL) {
/* Handle RxFIFO Non-Empty interrupt */
dwc2_handle_rxflvl(dev);
}
if (int_status & USB_DWC2_GINTSTS_OEPINT) { if (int_status & USB_DWC2_GINTSTS_OEPINT) {
/* Handle OUT Endpoints interrupt */ /* Handle OUT Endpoints interrupt */
dwc2_handle_oepint(dev); dwc2_handle_oepint(dev);