Skip to content

musb: improve endpoint 0 implementation approach#3626

Open
tzy0002088 wants to merge 1 commit intohathach:masterfrom
tzy0002088:musb_update
Open

musb: improve endpoint 0 implementation approach#3626
tzy0002088 wants to merge 1 commit intohathach:masterfrom
tzy0002088:musb_update

Conversation

@tzy0002088
Copy link
Copy Markdown

@tzy0002088 tzy0002088 commented Apr 29, 2026

All interrupt flags for MUSB Endpoint 0 (EP0) are contained within a single register. Occasionally, multiple EP0 states may be satisfied simultaneously, causing them to be merged into a single interrupt request sent to the CPU. In such cases, the driver must be capable of handling these concurrent conditions.

Due to heavy system load, global interrupts might be disabled elsewhere. Since the MUSB IP utilizes level-triggered interrupts, multiple internal events that should have triggered separate interrupts may become pending. Consequently, the CPU services them as a single interrupt request once global interrupts are re-enabled.

Instead of asserting distinct interrupts for the Data and Status stages in the blue region, the MUSB controller aggregated these pending flags into the following Setup stage interrupt request.

Capture of normal transfer without racing, IRQ (blue trace) triggered after each transfer stage.
83c26e364686c32ada705f8e2feb8406

When CPU is heavily loaded, IRQs are not served in time, we see only one IRQ fired at the end with multiples flags pending.
bcb497da-5c96-47c8-b38f-a037ea9e5c74

The Status stage complete interrupt was delayed into the Setup stage of the subsequent packet, followed by the triggering of the Setup interrupt

f839dde167fecffcc530a72f2ea85442

@tzy0002088 tzy0002088 force-pushed the musb_update branch 2 times, most recently from 8386648 to 23a8a89 Compare April 29, 2026 15:09
@HiFiPhile
Copy link
Copy Markdown
Collaborator

@Hathath PR author raised EP0 racing issue to me prior #3605 in a discussion group. He made the change but the branch is too old (with their own SOC) to be applied cleanly, so he has extracted the EP0 part.

@github-actions
Copy link
Copy Markdown

MemBrowse Memory Report

Top 10 targets by memory change (%) (out of 2233 targets) View Project Dashboard →

target .text .rodata .data .bss total % diff
msp_exp432e401y/dfu_runtime 8,836 → 9,036 (+200) 1,044 → 1,060 (+16) 10,612 → 10,828 (+216) +2.0%
msp_exp432e401y/hid_generic_inout 9,908 → 10,112 (+204) 1,248 → 1,264 (+16) 11,888 → 12,108 (+220) +1.9%
msp_exp432e401y/hid_multiple_interface 10,692 → 10,896 (+204) 1,124 → 1,140 (+16) 12,548 → 12,768 (+220) +1.8%
msp_exp432e401y/hid_boot_interface 10,704 → 10,908 (+204) 1,124 → 1,140 (+16) 12,560 → 12,780 (+220) +1.8%
msp_exp432e401y/hid_composite 10,916 → 11,120 (+204) 1,112 → 1,128 (+16) 12,760 → 12,980 (+220) +1.7%
msp_exp432e401y/midi_test 11,024 → 11,224 (+200) 1,244 → 1,260 (+16) 13,000 → 13,216 (+216) +1.7%
ek_tm4c123gxl/dfu_runtime 8,808 → 9,004 (+196) 608 → 624 (+16) 13,576 → 13,788 (+212) +1.6%
msp_exp432e401y/cdc_dual_ports 11,864 → 12,064 (+200) 1,428 → 1,444 (+16) 14,024 → 14,240 (+216) +1.5%
msp_exp432e401y/printer_to_cdc 11,996 → 12,196 (+200) 1,408 → 1,424 (+16) 14,128 → 14,344 (+216) +1.5%
msp_exp432e401y/webusb_serial 12,372 → 12,576 (+204) 1,416 → 1,432 (+16) 14,520 → 14,740 (+220) +1.5%

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reworks the MUSB device controller’s Endpoint 0 (control) handling to better tolerate merged/level-triggered EP0 interrupt conditions under heavy CPU load, by replacing the prior EP0 state handling with an explicit stage-based EP0 state machine.

Changes:

  • Replaces the prior EP0 state tracking with a new ep0_state_t (SETUP/DATA/STATUS stages) and updates dcd_data_t accordingly.
  • Reimplements edpt0_xfer() and process_ep0() around the new EP0 stage machine and adds ep0_setup() helper.
  • Adjusts reset, stall, and set-address flows to use the new EP0 state fields.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +484 to +489
if (_dcd.remaining_ctrl) {
dcd_event_xfer_complete(rhport,
tu_edpt_addr(0, TUSB_DIR_IN),
_dcd.pipe0.length - _dcd.pipe0.remaining,
XFER_RESULT_SUCCESS, true);
}
Comment thread src/portable/mentor/musb/dcd_musb.c Outdated
Comment on lines +471 to +473
TU_LOG3(false, "SetupEnd came in a wrong ep0stage %s\n", _dcd.ep0_state);
}
csrl = _dcd.ep0_state;
Comment thread src/portable/mentor/musb/dcd_musb.c Outdated
if (_dcd.setup_packet.wLength == 0) {
/* No data stage, must send zlp to host */
_dcd.ep0_state = USB_EP0_STAGE_PRE_STATUSIN;
if (_dcd.setup_packet.bRequest == 5) {
Comment thread src/portable/mentor/musb/dcd_musb.c Outdated
ep_csr->csr0l = MUSB_CSRL0_RXRDYC;
while ((ep_csr->csr0l & MUSB_CSRL0_RXRDY) != 0);
} else {
/* OUT stage, recive data from host */
Comment on lines +450 to +452
if (csrl & MUSB_CSRL0_DATAEND) {
return;
}
Comment on lines +371 to +384
const unsigned rem = _dcd.remaining_ctrl;
const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes);
tu_hwfifo_write(&musb_regs->fifo[0], buffer, len, NULL);

_dcd.pipe0.buf = buffer + len;
_dcd.pipe0.length = len;
_dcd.pipe0.remaining = 0;

_dcd.remaining_ctrl = rem - len;
if ((len < 64) || (rem == len)) {
_dcd.ep0_state = USB_EP0_STAGE_STATUSOUT;
ep_csr->csr0l = MUSB_CSRL0_TXRDY | MUSB_CSRL0_DATAEND;
} else {
_dcd.ep0_state = USB_EP0_STAGE_TX;
// First event of the STATUS OUT pair — wait for the IRQ to fire complete.
_dcd.pipe0.state = PIPE0_STATE_STATUS_OUT_PENDING;
break;
while (ep_csr->count0 != 8);
Comment on lines +499 to +500
const unsigned len = TU_MIN(TU_MIN(rem, 64), vld);
tu_hwfifo_read(&musb_regs->fifo[0], _dcd.pipe0.buf, len, NULL);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants