Skip to content

[update] port: hpmicro: dcd: using sutw semaphore by isr handler for …#410

Merged
sakumisu merged 1 commit intocherry-embedded:masterfrom
chenzhihong007:master
Apr 13, 2026
Merged

[update] port: hpmicro: dcd: using sutw semaphore by isr handler for …#410
sakumisu merged 1 commit intocherry-embedded:masterfrom
chenzhihong007:master

Conversation

@chenzhihong007
Copy link
Copy Markdown
Contributor

@chenzhihong007 chenzhihong007 commented Apr 13, 2026

…setup

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Enhanced USB device setup request handling for improved reliability
    • Improved error reporting for USB transfer operations
    • Optimized USB reset event processing
    • Enhanced transfer completion length tracking for USB endpoints

…setup

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 13, 2026

📝 Walkthrough

Walkthrough

Modified the USB device controller interrupt handler to introduce a static buffer for EP0 setup data with synchronization logic, update endpoint error codes to use standardized USB error constants, add an early return for bus reset events, and accumulate actual transfer lengths for completed QTDs.

Changes

Cohort / File(s) Summary
USB Device Controller Setup & Transfer Handling
port/hpmicro/usb_dc_hpm.c
Modified EP0 setup packet handling with static buffer and synchronization flag (usb_dcd_get_sutw/usb_dcd_set_sutw), replaced magic numbers (-1, -2) with standardized USB error codes (-USB_ERR_NOMEM, -USB_ERR_NOTCONN, -USB_ERR_INVAL), added early reset return in IRQHandler, and updated transfer length accumulation logic for completed QTDs to write to actual_xfer_len for both endpoint directions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 The setup buffer waits with grace,
Synchronization finds its place,
Error codes now shine so bright,
Transfer lengths done just right,
USB dance now flows with might! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title refers to a real aspect of the changes (sutw semaphore handling in ISR) but is incomplete (ends with 'for …') and somewhat vague about the primary impact of all modifications. Complete the title and clarify the main objective. Consider: 'Fix EP0 setup handling and error codes in hpmicro USB DCD' or similar to better reflect all significant changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@port/hpmicro/usb_dc_hpm.c`:
- Around line 240-241: The check "if (!data && data_len)" currently returns
-USB_ERR_NOMEM which is wrong; change it to return an invalid-argument error
(e.g., -USB_ERR_INVAL or the project-specific invalid-argument constant) so
callers get a parameter error instead of an out-of-memory error; update both
occurrences of this condition in usb_dc_hpm.c (the "if (!data && data_len)"
branches) to return the chosen invalid-argument error constant and keep the rest
of the logic unchanged.
- Line 49: _setup_data is a global 8-byte scratch buffer shared across
controller instances which can be clobbered if one ISR preempts another between
memcpy() and usbd_event_ep0_setup_complete_handler(); change it to be per-bus
instead: replace the global static uint8_t _setup_data[8] with either a local
stack buffer used where memcpy() is called and then immediately pass to
usbd_event_ep0_setup_complete_handler(), or allocate a per-bus buffer like
uint8_t setup_data[CONFIG_USBDEV_MAX_BUS][8] indexed by the controller/bus id
used by the port code, and update all uses (the memcpy call and any references
at the locations around lines 401-405 and the EP0 handling path) to use the
bus-specific buffer. Ensure the core still receives a synchronous copy so
semantics remain unchanged.
- Around line 398-403: Move the call to usb_device_clear_setup_status so it
happens after the SUTW-protected read to avoid a race where a second SETUP can
overwrite qhd0->setup_request during memcpy. Specifically, keep the do/while
that asserts usb_dcd_set_sutw(handle->regs, true), copies the 8 bytes from
qhd0->setup_request into _setup_data using memcpy, loops on
usb_dcd_get_sutw(handle->regs), and then clear SUTW and only after SUTW is
deasserted call usb_device_clear_setup_status(handle, edpt_setup_status); ensure
usb_dcd_set_sutw(handle->regs, false) remains adjacent to the protected read so
the setup-clear happens after the protected read completes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ee7381b2-7753-47a1-aa56-fe0629034b1f

📥 Commits

Reviewing files that changed from the base of the PR and between 8635094 and d1a2c24.

📒 Files selected for processing (1)
  • port/hpmicro/usb_dc_hpm.c

Comment thread port/hpmicro/usb_dc_hpm.c
static USB_NOCACHE_RAM_SECTION ATTR_ALIGN(USB_SOC_DCD_DATA_RAM_ADDRESS_ALIGNMENT)
uint8_t _dcd_data[CONFIG_USBDEV_MAX_BUS][HPM_ALIGN_UP(sizeof(dcd_data_t), USB_SOC_DCD_DATA_RAM_ADDRESS_ALIGNMENT)];
static USB_NOCACHE_RAM_SECTION usb_device_handle_t usb_device_handle[CONFIG_USBDEV_MAX_BUS];
static uint8_t _setup_data[8];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Make the EP0 scratch buffer per bus, not global.

_setup_data is shared by every controller instance, but this port already supports multiple buses. If one USB ISR preempts another between the memcpy() and usbd_event_ep0_setup_complete_handler(), the later SETUP packet can overwrite the buffer and deliver the wrong request to core. core/usbd_core.c copies the 8 bytes synchronously, so a stack buffer or [CONFIG_USBDEV_MAX_BUS][8] buffer is enough.

Suggested fix
-static uint8_t _setup_data[8];
+static uint8_t _setup_data[CONFIG_USBDEV_MAX_BUS][8];
...
-                memcpy(_setup_data, (uint8_t *)(&qhd0->setup_request), 8);
+                memcpy(_setup_data[busid], (uint8_t *)(&qhd0->setup_request), 8);
...
-            usbd_event_ep0_setup_complete_handler(busid, _setup_data);
+            usbd_event_ep0_setup_complete_handler(busid, _setup_data[busid]);

Also applies to: 401-405

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@port/hpmicro/usb_dc_hpm.c` at line 49, _setup_data is a global 8-byte scratch
buffer shared across controller instances which can be clobbered if one ISR
preempts another between memcpy() and usbd_event_ep0_setup_complete_handler();
change it to be per-bus instead: replace the global static uint8_t
_setup_data[8] with either a local stack buffer used where memcpy() is called
and then immediately pass to usbd_event_ep0_setup_complete_handler(), or
allocate a per-bus buffer like uint8_t setup_data[CONFIG_USBDEV_MAX_BUS][8]
indexed by the controller/bus id used by the port code, and update all uses (the
memcpy call and any references at the locations around lines 401-405 and the EP0
handling path) to use the bus-specific buffer. Ensure the core still receives a
synchronous copy so semantics remain unchanged.

Comment thread port/hpmicro/usb_dc_hpm.c
Comment on lines 240 to +241
if (!data && data_len) {
return -1;
return -USB_ERR_NOMEM;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Return an invalid-argument error for NULL + nonzero length.

This is caller misuse, not allocator exhaustion. Reporting -USB_ERR_NOMEM makes it harder for callers to distinguish a bad API contract from real resource pressure.

Suggested fix
     if (!data && data_len) {
-        return -USB_ERR_NOMEM;
+        return -USB_ERR_INVAL;
     }

Also applies to: 267-268

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@port/hpmicro/usb_dc_hpm.c` around lines 240 - 241, The check "if (!data &&
data_len)" currently returns -USB_ERR_NOMEM which is wrong; change it to return
an invalid-argument error (e.g., -USB_ERR_INVAL or the project-specific
invalid-argument constant) so callers get a parameter error instead of an
out-of-memory error; update both occurrences of this condition in usb_dc_hpm.c
(the "if (!data && data_len)" branches) to return the chosen invalid-argument
error constant and keep the rest of the logic unchanged.

Comment thread port/hpmicro/usb_dc_hpm.c
Comment on lines +398 to +403
usb_device_clear_setup_status(handle, edpt_setup_status);
do {
usb_dcd_set_sutw(handle->regs, true);
memcpy(_setup_data, (uint8_t *)(&qhd0->setup_request), 8);
} while (!usb_dcd_get_sutw(handle->regs));
usb_dcd_set_sutw(handle->regs, false);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

For the HPMicro USB device controller / EHCI device controller, what is the recommended ordering when reading EP0 setup data with the SUTW (setup tripwire) bit relative to clearing ENDPTSETUPSTAT / setup status?

💡 Result:

No definitive source explicitly states the recommended ordering for reading EP0 setup data with the SUTW (setup tripwire) bit relative to clearing ENDPTSETUPSTAT/setup status in the HPMicro USB device controller / EHCI device controller. The HPMicro SDK documentation and official website do not provide detailed register descriptions matching these exact terms (SUTW, ENDPTSETUPSTAT), which are typical of Freescale/NXP USB controllers (e.g., in Kinetis or i.MX series). HPMicro's USB IP appears to be a custom implementation supporting TinyUSB and USBX stacks, but specific programming guidance for setup packet handling is not publicly documented in searched sources. In standard Freescale/NXP USB device controllers (similar terminology), the recommended sequence is: 1. Read EP0 setup data from the OEPCTLx/SEPCTLx registers or FIFO. 2. Clear the setup status bit (ENDPTSETUPSTAT) in ENDPOINTSTATUS register. The SUTW bit prevents further setups until cleared, ensuring data integrity. Clearing before reading risks missing or corrupting the setup data. Without HPMicro-specific confirmation, follow the NXP/Freescale convention: read setup data first, then clear the setup status.

Citations:


🏁 Script executed:

# First, let's find and examine the file
file_path="port/hpmicro/usb_dc_hpm.c"
if [ -f "$file_path" ]; then
  echo "=== File found, examining lines 390-410 ==="
  sed -n '390,410p' "$file_path" | cat -n
else
  echo "File not found at $file_path"
  # Try to find it
  echo "Searching for usb_dc_hpm.c..."
  find . -name "usb_dc_hpm.c" -type f
fi

Repository: cherry-embedded/CherryUSB

Length of output: 854


🏁 Script executed:

# Search for _setup_data declaration to understand its type
echo "=== Searching for _setup_data declaration ==="
rg "_setup_data" -B 2 -A 2 --max-count=10

Repository: cherry-embedded/CherryUSB

Length of output: 1106


🏁 Script executed:

# Examine the function containing lines 398-403
echo "=== Examining function context around line 398 ==="
sed -n '370,430p' "$file_path" | cat -n

Repository: cherry-embedded/CherryUSB

Length of output: 180


🏁 Script executed:

# Check if there are per-bus setup data buffers
rg "setup_data" -B 3 -A 3 port/hpmicro/usb_dc_hpm.c

Repository: cherry-embedded/CherryUSB

Length of output: 899


🏁 Script executed:

# Check how CONFIG_USBDEV_MAX_BUS is used and if there should be per-bus buffers
rg "CONFIG_USBDEV_MAX_BUS" port/hpmicro/usb_dc_hpm.c

Repository: cherry-embedded/CherryUSB

Length of output: 317


🏁 Script executed:

# Look at the function signature to understand busid context
sed -n '350,400p' port/hpmicro/usb_dc_hpm.c | cat -n

Repository: cherry-embedded/CherryUSB

Length of output: 2819


🏁 Script executed:

# Double-check by looking at other similar USB controller drivers to see if _setup_data should be per-bus
rg "_setup_data\[" port/ || echo "No indexed _setup_data found"

Repository: cherry-embedded/CherryUSB

Length of output: 125


🏁 Script executed:

# Check how this interrupt handler is structured and if busid race condition exists
grep -n "usbd_event_ep0_setup_complete_handler" port/hpmicro/usb_dc_hpm.c

Repository: cherry-embedded/CherryUSB

Length of output: 143


Move usb_device_clear_setup_status() after the SUTW-protected read.

The current code acknowledges the EP0 setup status before the SUTW-protected read completes, opening a race condition where a second SETUP can corrupt qhd0->setup_request while the memcpy is in progress. This can cause the wrong request to be forwarded or a setup packet to be skipped entirely. The clear operation must be moved until after the do/while loop completes, while SUTW is still asserted.

Suggested fix
             do {
                 usb_dcd_set_sutw(handle->regs, true);
                 memcpy(_setup_data, (uint8_t *)(&qhd0->setup_request), 8);
             } while (!usb_dcd_get_sutw(handle->regs));
+            usb_device_clear_setup_status(handle, edpt_setup_status);
             usb_dcd_set_sutw(handle->regs, false);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@port/hpmicro/usb_dc_hpm.c` around lines 398 - 403, Move the call to
usb_device_clear_setup_status so it happens after the SUTW-protected read to
avoid a race where a second SETUP can overwrite qhd0->setup_request during
memcpy. Specifically, keep the do/while that asserts
usb_dcd_set_sutw(handle->regs, true), copies the 8 bytes from
qhd0->setup_request into _setup_data using memcpy, loops on
usb_dcd_get_sutw(handle->regs), and then clear SUTW and only after SUTW is
deasserted call usb_device_clear_setup_status(handle, edpt_setup_status); ensure
usb_dcd_set_sutw(handle->regs, false) remains adjacent to the protected read so
the setup-clear happens after the protected read completes.

@sakumisu sakumisu merged commit 9938fbf into cherry-embedded:master Apr 13, 2026
5 of 6 checks passed
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.

2 participants