dakejahl opened a new pull request, #19936:
URL: https://github.com/apache/nuttx/pull/19936
## Summary
The Synopsys DWC2-derived USB device drivers enable `USBSUSP` in `GINTMSK`
but not `WKUP`, and every one of them ANDs `GINTSTS` with `GINTMSK` at the top
of its ISR before dispatching. The `WKUP` branch and the `*_resumeinterrupt()`
it calls are therefore dead code: `CLASS_SUSPEND` is delivered, `CLASS_RESUME`
never is.
For CDC/ACM the asymmetry is fatal rather than merely lossy.
`cdcacm_suspend()` calls `uart_connected(&priv->serdev, false)`, and from then
on `serial.c` refuses every board-side `open()` and `write()` with `-ENOTCONN`.
The `cdcacm_resume()` that would call `uart_connected(true)` never runs, so the
port stays unusable for the rest of the boot even though the device remains
enumerated and the host has long since resumed it.
Adding `WKUP` to the mask makes the existing handler reachable. The status
bit is already acknowledged in the same read/ack cycle as the rest of the
writable interrupts, so unmasking it cannot latch.
The second commit adds `tools/usbdev_suspend_test.py`, the host-side script
used to characterise this.
## Impact
Affects any board whose USB device controller is one of these eight drivers
and whose host suspends it. Linux hosts do that by default: with
`power/control=auto` and the usual `autosuspend_delay_ms=2000`, closing the tty
is enough. Software that opens, reads and closes the port — as opposed to
holding it open — kills the link on the first close, which is why this reads as
an intermittent wedge rather than a deterministic bug.
No configuration, API or wire-format change. One extra interrupt source per
suspend/resume, handled by code already present.
Drivers touched:
```
arch/arm/src/at32/at32_otgfsdev.c
arch/arm/src/common/stm32/stm32_otgfsdev_m3m4_v1.c
arch/arm/src/common/stm32/stm32_otghsdev_m3m4_v1.c
arch/arm/src/efm32/efm32_usbdev.c
arch/arm/src/stm32f7/stm32_otgdev.c
arch/arm/src/stm32h7/stm32_otgdev.c
arch/arm/src/stm32l4/stm32l4_otgfsdev.c
arch/xtensa/src/esp32s3/esp32s3_otg_device.c
```
## Testing
**Host:** Linux 7.0.0-28-generic x86_64, xhci_hcd, `usbcore.autosuspend=2`.
**Board:** ARK FMU v6X (STM32H743), `CONFIG_STM32H7_OTGFS=y`,
`CONFIG_CDCACM=y` (which `select`s `SERIAL_REMOVABLE`), NuttX 11.0.0 under PX4.
Console on a separate STLINK-V3 VCP so it survives the CDC port dying.
Only the STM32H7 path was exercised on hardware. The other seven drivers
carry a line-for-line copy of the same `GINTMSK` initialisation and the same
masked-off resume handler.
Each cycle below forces a verified runtime suspend, resumes the device by
opening the port, reads for 2 s, then asks the board over its console whether
the CDC port is writable again.
Before:
```
$ ./tools/usbdev_suspend_test.py -d
/dev/serial/by-id/usb-ARK_ARK_FMU_v6X.x_0-if00 \
-n 5 --console /dev/ttyACM0 --console-baud 57600
device /dev/serial/by-id/usb-ARK_ARK_FMU_v6X.x_0-if00 -> /dev/ttyACM1
usb 1-5.4 3185:0039 ARK FMU v6X.x
power control=on autosuspend_delay_ms=2000 (restored on exit)
[1] suspended=True read=12179 tail=0 board-side open failed:
-ENOTCONN
[2] suspended=True read=0 tail=0 board-side open failed:
-ENOTCONN
[3] suspended=True read=0 tail=0 board-side open failed:
-ENOTCONN
[4] suspended=True read=0 tail=0 board-side open failed:
-ENOTCONN
[5] suspended=True read=0 tail=0 board-side open failed:
-ENOTCONN
cycles with a verified suspend: 5/5
of those, still streaming after resume: 0/5
FAIL: the link died after suspend and did not come back.
```
The 12179 bytes on the first cycle are the stale
`CONFIG_CDCACM_TXBUFSIZE=12000` TX buffer flushing on resume, not a working
link — hence `tail=0`, the bytes seen in the last second of the window.
After:
```
[1] suspended=True read=40898 tail=23316 board-side open ok
[2] suspended=True read=42441 tail=22020 board-side open ok
[3] suspended=True read=36945 tail=20372 board-side open ok
[4] suspended=True read=44866 tail=22897 board-side open ok
[5] suspended=True read=37565 tail=20480 board-side open ok
cycles with a verified suspend: 5/5
of those, still streaming after resume: 5/5
PASS: the link recovered from every suspend.
```
Board side on the unpatched build, after a single host suspend, the port is
gone for good:
```
nsh> echo hi > /dev/ttyACM0
nsh: echo: open failed: Transport endpoint is not connected
```
Patched, the same command succeeds once the host resumes, and a 22 s suspend
is followed by full recovery of the CDC stream (`tx 21946 B/s`, `txerr 0.0
B/s`, 217 kB read by the host over the following 10 s).
Build-tested beyond STM32H7: `cubepilot_cubeyellow` (stm32f7 OTGFS),
`airmind_mindpx-v2` (common/stm32 OTGFS), `matek_gnss-m9n-f4` (common/stm32
OTGHS).
`./tools/checkpatch.sh -c -u -m -g master..HEAD` passes.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]