-
Notifications
You must be signed in to change notification settings - Fork 1.3k
dcd/dwc2: fix EP0 multi-packet transfer logic #3295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…m_packets = 1 Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
There was a problem hiding this 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 fixes EP0 multi-packet transfer logic in the DWC2 driver and adds configurable EP0 buffer size support. The issue was in the edpt_schedule_packets function where ep0_pending was incorrectly being set to xfer->max_size instead of the proper endpoint size, causing transfer size calculation errors.
Key changes:
- Added
CFG_TUD_EP0_BUFSIZEconfiguration option for EP0 buffer size - Fixed EP0 packet scheduling logic to use correct endpoint size
- Enhanced packet transmission handling for single vs multi-packet transfers
- Updated DFU examples with BOS descriptors and Microsoft OS 2.0 compatibility
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/tusb_option.h | Added CFG_TUD_EP0_BUFSIZE configuration option |
| src/portable/synopsys/dwc2/dcd_dwc2.c | Fixed EP0 transfer logic and improved packet handling |
| src/device/usbd_control.c | Updated to use new CFG_TUD_EP0_BUFSIZE configuration |
| examples/device/dfu_runtime/src/usb_descriptors.c | Added BOS descriptor and Microsoft OS 2.0 support |
| examples/device/dfu/src/usb_descriptors.c | Added BOS descriptor and Microsoft OS 2.0 support |
Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
…to/from use EP0 buffer. Signed-off-by: HiFiPhile <admin@hifiphile.com>
# Conflicts: # examples/device/dfu/src/usb_descriptors.c # examples/device/dfu_runtime/src/usb_descriptors.c # src/portable/synopsys/dwc2/dcd_dwc2.c
src/device/usbd_control.c
Outdated
| // a short packet is sent including zero-length packet. | ||
| if ((_ctrl_xfer.request.wLength == _ctrl_xfer.total_xferred) || | ||
| (xferred_bytes < CFG_TUD_ENDPOINT0_SIZE)) { | ||
| (xferred_bytes < CFG_TUD_EP0_BUFSIZE)) { |
Check warning
Code scanning / C-STAT
The operands `xferred_bytes' and `CFG_TUD_ENDPOINT0_SIZE' have essential type categories unsigned 32-bit int and signed 8-bit int, which do not match
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forgot most of the dwc2 driver, didn't re-check the specs. These are 2 things pop-up in my mind when we are making control transfer faster like bulk.
PS: also I enable a few code scanning tools (free for OSS), still testing it out, so it can be very verbose atm
| // Enable tx fifo empty interrupt only if there is data. Note must after depctl enable | ||
| if (dir == TUSB_DIR_IN && total_bytes != 0) { | ||
| dwc2->diepempmsk |= (1u << epnum); | ||
| // For num_packets = 1 we write the packet directly |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should keep using the TXFE interrupt to write to fifo. Otherwise there could be race condition whereas usbd mis-manage control transfer, and we are attempting to xfer on busy endpoint0.
also I think we need to also increase (double) the dfifo_alloc() for EP0 when the EP0_BUFSIZE is large enough e.g 8x64 bytes since user is clearly want to make a large transfer with EP0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should keep using the TXFE interrupt to write to fifo. Otherwise there could be race condition whereas usbd mis-manage control transfer, and we are attempting to xfer on busy endpoint0.
I think it should be safe, which scenario you are thinking about ?
also I think we need to also increase (double) the dfifo_alloc() for EP0 when the EP0_BUFSIZE is large enough e.g 8x64 bytes since user is clearly want to make a large transfer with EP0
EP0 IN can only queue 3 packets each time, EP0 OUT can only queue 1 packet each time, so increasing the fifo won't have much help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be safe, which scenario you are thinking about ?
You are right, I just feel a bit un-easy when both handle_epin_slave() and edpt_schedule_packets() can write to difof. Especially handle_epin_slave() also called edpt_schedule_packets() in case of ep0. But it is probably safe enough, actually we can refactor this and try to write as many packet as we could before enable the TX empty if there is remaining packet ?
dwc2_ep_tsize_t tsiz = {.value = epin->tsiz};
const uint16_t remain_packets = tsiz.packet_count;
// Process every single packet (only whole packets can be written to fifo)
for (uint16_t i = 0; i < remain_packets; i++) {
tsiz.value = epin->tsiz;
const uint16_t remain_bytes = (uint16_t) tsiz.xfer_size;
const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size);
// Check if dtxfsts has enough space available
if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) {
break;
}
// Push packet to Tx-FIFO
if (xfer->ff) {
volatile uint32_t* tx_fifo = dwc2->fifo[epnum];
tu_fifo_read_n_const_addr_full_words(xfer->ff, (void*)(uintptr_t)tx_fifo, xact_bytes);
} else {
dfifo_write_packet(dwc2, epnum, xfer->buffer, xact_bytes);
xfer->buffer += xact_bytes;
}
}EP0 IN can only queue 3 packets each time, EP0 OUT can only queue 1 packet each time, so increasing the fifo won't have much help.
right, again, I am too lazy to check the specs, the increased ep0 bufsize only help to reduce the overhead when pushing isr --> usbd event stack. Let keep the ep0 1 packet per xfer is good enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've refactored the fifo writing routine and added a tunable CFG_TUD_DWC2_IN_DOUBLE_BUFFER to set GAHBCFG_TX_FIFO_EPMTY_LVL and fifo allocation, in order to allow writing 2 packets to fifo.
By default we allocate fifo size=packet size, the writing loop will likely stop after one packet is written.
Signed-off-by: Mengsk <admin@hifiphile.com>
src/tusb_option.h
Outdated
|
|
||
| // Allocate double buffer for IN endpoint for better performance (only applies to non-periodic endpoints) | ||
| #ifndef CFG_TUD_DWC2_IN_DOUBLE_BUFFER | ||
| #define CFG_TUD_DWC2_IN_DOUBLE_BUFFER 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should not introduce this option. I always think the fine-tune fifo should be dictated by application per endpoint basic. E.g MSC + CDC, we would want a massive endpoint size for msc and smaller for cdc. I am think we should do that via a tud_configure() (which allo to pass an option id + pointer to struct) that fine tune the behavior of dcd or stack. similar to tuh_configure() https://github.com/hathach/tinyusb/blob/master/src/host/usbh.h#L145 . dwc2 option may include grxsize and txfifo size for each endpoint (0 for auto as current).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah a configurable parameter is better, didn't notice there is a tuh_configure().
Signed-off-by: HiFiPhile <admin@hifiphile.com>
Signed-off-by: HiFiPhile <admin@hifiphile.com>
# Conflicts: # examples/device/dfu/src/usb_descriptors.c # examples/device/dfu_runtime/src/usb_descriptors.c # src/device/usbd_control.c # src/portable/synopsys/dwc2/dcd_dwc2.c
use uint8_t for dfu state and status to reduce size
|
@hathach I'm think about when |
|
yeah, though I think we can do it in follow up Pr. |
hathach
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perfect thank you

Describe the PR
There was an issue in
edpt_schedule_packets, asep0_pending = xfer->max_sizeis set indcd_edpt_xfer, ep0_pending will become 0.The issue didn't broken since we schedule only one control transfer each time.
I've add an option
CFG_TUD_EP0_BUFSIZEto allow setting EP0 buffer size individually, tested with DFU examples withCFG_TUD_EP0_BUFSIZE=512