Skip to content

Conversation

@CV-Bowen
Copy link
Contributor

Summary

This PR adds power management (PM) support to the rpmsg virtio driver for multi-core low power scenarios.

Why is this needed?

In multi-core systems where TX/RX buffers are supplied and powered by each CPU independently, when one CPU enters DEEP sleep mode, its buffer goes into RAM-retention mode and becomes inaccessible from another CPU. This causes communication failures and potential system hangs.

What does this PR do?

  1. Adds CONFIG_RPMSG_VIRTIO_PM Kconfig option to enable PM support
  2. Adds CONFIG_RPMSG_VIRTIO_PM_AUTORELAX option for automatic wakelock release via watchdog timer
  3. Implements PM wakelock mechanism:
    • Acquires wakelock when sending data (tx notify)
    • Releases wakelock when all TX buffers are returned by peer
  4. Adds buffer tracking (headrx) to check RX availability before processing
  5. Uses spinlock protection for PM state transitions

Key changes:

  • New Kconfig options for PM configuration
  • PM wakelock integration with pm_wakelock_stay/relax
  • Watchdog timer for automatic wakelock release (20ms timeout)
  • TX notify hook to track outgoing messages
  • Enhanced dump output with headrx info for debugging

Impact

  • Stability: Improves system stability in low power multi-core scenarios by preventing buffer access during RAM-retention
  • Compatibility: No impact when CONFIG_RPMSG_VIRTIO_PM is disabled (default)
  • Performance: Minimal overhead - only adds PM operations on TX/RX paths when enabled
  • Breaking Changes: None

Testing

Build Verification:

Build both server and proxy images

cmake -B cmake_out/v8a_server -DBOARD_CONFIG=qemu-armv8a:v8a_server -GNinja
cmake --build cmake_out/v8a_server

cmake -B cmake_out/v8a_proxy -DBOARD_CONFIG=qemu-armv8a:v8a_proxy -GNinja
cmake --build cmake_out/v8a_proxy

Test Environment:
Host: Ubuntu 22.04 x86_64
Target: QEMU ARM64 dual-core (qemu-armv8a:v8a_server + v8a_proxy)
Communication: ivshmem shared memory + virtio-serial socket
Start Server (Terminal 1):

qemu-system-aarch64 -cpu cortex-a53 -nographic \
  -machine virt,virtualization=on,gic-version=3 \
  -chardev stdio,id=con,mux=on -serial chardev:con \
  -object memory-backend-file,discard-data=on,id=shmmem-shmem0,mem-path=/dev/shm/my_shmem0,size=4194304,share=yes \
  -device ivshmem-plain,id=shmem0,memdev=shmmem-shmem0,addr=0xb \
  -device virtio-serial-device,bus=virtio-mmio-bus.0 \
  -chardev socket,path=/tmp/rpmsg_port_uart_socket,server=on,wait=off,id=foo \
  -device virtconsole,chardev=foo \
  -mon chardev=con,mode=readline -kernel ./nuttx/cmake_out/v8a_server/nuttx
Start Proxy (Terminal 2):

qemu-system-aarch64 -cpu cortex-a53 -nographic \
  -machine virt,virtualization=on,gic-version=3 \
  -chardev stdio,id=con,mux=on -serial chardev:con \
  -object memory-backend-file,discard-data=on,id=shmmem-shmem0,mem-path=/dev/shm/my_shmem0,size=4194304,share=yes \
  -device ivshmem-plain,id=shmem0,memdev=shmmem-shmem0,addr=0xb \
  -device virtio-serial-device,bus=virtio-mmio-bus.0 \
  -chardev socket,path=/tmp/rpmsg_port_uart_socket,server=off,id=foo \
  -device virtconsole,chardev=foo \
  -mon chardev=con,mode=readline -kernel ./nuttx/cmake_out/v8a_proxy/nuttx

Log:

qemu-system-aarch64 -cpu cortex-a53 -nographic \
-machine virt,virtualization=on,gic-version=3 \
-chardev stdio,id=con,mux=on -serial chardev:con \
-object memory-backend-file,discard-data=on,id=shmmem-shmem0,mem-path=/dev/shm/my_shmem0,size=4194304,share=yes \
-device ivshmem-plain,id=shmem0,memdev=shmmem-shmem0,addr=0xb \
-device virtio-serial-device,bus=virtio-mmio-bus.0 \
-chardev socket,path=/tmp/rpmsg_port_uart_socket,server=on,wait=off,id=foo \
-device virtconsole,chardev=foo \
-mon chardev=con,mode=readline -kernel ./nuttx/cmake_out/v8a_server/nuttx \
-gdb tcp::7775
[    0.000000] [ 0] [  INFO] [server] pci_register_rptun_ivshmem_driver: Register ivshmem driver, id=0, cpuname=proxy, master=1
[    0.000000] [ 3] [  INFO] [server] pci_scan_bus: pci_scan_bus for bus 0
[    0.000000] [ 3] [  INFO] [server] pci_scan_bus: class = 00000600, hdr_type = 00000000
[    0.000000] [ 3] [  INFO] [server] pci_scan_bus: 00:00 [1b36:0008]
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar0 set bad mask
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar1 set bad mask
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar2 set bad mask
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar3 set bad mask
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar4 set bad mask
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar5 set bad mask
[    0.000000] [ 3] [  INFO] [server] pci_scan_bus: class = 00000200, hdr_type = 00000000
[    0.000000] [ 3] [  INFO] [server] pci_scan_bus: 00:08 [1af4:1000]
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar0: mask64=fffffffe 32bytes
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar1: mask64=fffffff0 4096bytes
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar2 set bad mask
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar3 set bad mask
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar4: mask64=fffffffffffffff0 16384bytes
[    0.000000] [ 3] [  INFO] [server] pci_scan_bus: class = 00000500, hdr_type = 00000000
[    0.000000] [ 3] [  INFO] [server] pci_scan_bus: 00:58 [1af4:1110]
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar0: mask64=fffffff0 256bytes
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar1 set bad mask
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar2: mask64=fffffffffffffff0 4194304bytes
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar4 set bad mask
[    0.000000] [ 3] [  INFO] [server] pci_setup_device: pbar5 set bad mask
[    0.000000] [ 3] [  INFO] [server] ivshmem_probe: shmem addr=0x10400000 size=4194304 reg=0x10008000
[    0.000000] [ 3] [  INFO] [server] rptun_ivshmem_probe: shmem addr=0x10400000 size=4194304

NuttShell (NSH) NuttX-12.10.0
server> 
server> 
server> 
server> [    0.000000] [ 0] [  INFO] [proxy] pci_register_rptun_ivshmem_driver: Register ivshmem driver, id=0, cpuname=server, master=0
[    0.000000] [ 3] [  INFO] [proxy] pci_scan_bus: pci_scan_bus for bus 0
[    0.000000] [ 3] [  INFO] [proxy] pci_scan_bus: class = 00000600, hdr_type = 00000000
[    0.000000] [ 3] [  INFO] [proxy] pci_scan_bus: 00:00 [1b36:0008]
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar0 set bad mask
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar1 set bad mask
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar2 set bad mask
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar3 set bad mask
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar4 set bad mask
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar5 set bad mask
[    0.000000] [ 3] [  INFO] [proxy] pci_scan_bus: class = 00000200, hdr_type = 00000000
[    0.000000] [ 3] [  INFO] [proxy] pci_scan_bus: 00:08 [1af4:1000]
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar0: mask64=fffffffe 32bytes
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar1: mask64=fffffff0 4096bytes
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar2 set bad mask
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar3 set bad mask
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar4: mask64=fffffffffffffff0 16384bytes
[    0.000000] [ 3] [  INFO] [proxy] pci_scan_bus: class = 00000500, hdr_type = 00000000
[    0.000000] [ 3] [  INFO] [proxy] pci_scan_bus: 00:58 [1af4:1110]
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar0: mask64=fffffff0 256bytes
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar1 set bad mask
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar2: mask64=fffffffffffffff0 4194304bytes
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar4 set bad mask
[    0.000000] [ 3] [  INFO] [proxy] pci_setup_device: pbar5 set bad mask
[    0.000000] [ 3] [  INFO] [proxy] ivshmem_probe: shmem addr=0x10400000 size=4194304 reg=0x10008000
[    0.000000] [ 3] [  INFO] [proxy] rptun_ivshmem_probe: shmem addr=0x10400000 size=4194304
[    0.000000] [ 3] [  INFO] [proxy] rptun_ivshmem_probe: Start the wdog

server> 
server> 
server> 
server> rpmsg ping all 1 1 1 1
[    0.000000] [ 7] [ EMERG] [server] ping times: 1
[    0.000000] [ 7] [ EMERG] [server] buffer_len: 1520, send_len: 17
[    0.000000] [ 7] [ EMERG] [server] avg: 0 s, 16318208 ns
[    0.000000] [ 7] [ EMERG] [server] min: 0 s, 16318208 ns
[    0.000000] [ 7] [ EMERG] [server] max: 0 s, 16318208 ns
[    0.000000] [ 7] [ EMERG] [server] rate: 0.008334 Mbits/sec
[    0.000000] [ 7] [ EMERG] [server] ping times: 1
[    0.000000] [ 7] [ EMERG] [server] buffer_len: 2024, send_len: 17
[    0.000000] [ 7] [ EMERG] [server] avg: 0 s, 6929520 ns
[    0.000000] [ 7] [ EMERG] [server] min: 0 s, 6929520 ns
[    0.000000] [ 7] [ EMERG] [server] max: 0 s, 6929520 ns
[    0.000000] [ 7] [ EMERG] [server] rate: 0.019626 Mbits/sec
server> 
server> uname -a
NuttX server 12.10.0 04a9df8e34f Jan 20 2026 19:35:34 arm64 qemu-armv8a
server> rpmsg dump all
[    0.000000] [ 7] [ EMERG] [server] Local: server Remote: proxy Headrx 8
[    0.000000] [ 7] [ EMERG] [server] Dump rpmsg info between cpu (master: yes)server <==> proxy:
[    0.000000] [ 7] [ EMERG] [server] rpmsg vq RX:
[    0.000000] [ 7] [ EMERG] [server] rpmsg vq TX:
[    0.000000] [ 7] [ EMERG] [server]   rpmsg ept list:
[    0.000000] [ 7] [ EMERG] [server]     ept NS
[    0.000000] [ 7] [ EMERG] [server]     ept rpmsg-sensor
[    0.000000] [ 7] [ EMERG] [server]     ept rpmsg-ping
[    0.000000] [ 7] [ EMERG] [server]     ept rpmsg-syslog
[    0.000000] [ 7] [ EMERG] [server]   rpmsg buffer list:
[    0.000000] [ 7] [ EMERG] [server]     RX buffer, total 8, pending 0
[    0.000000] [ 7] [ EMERG] [server]     TX buffer, total 8, pending 0
[    0.000000] [ 7] [ EMERG] [server] Remote: proxy2 state: 1
[    0.000000] [ 7] [ EMERG] [server] ept NS
[    0.000000] [ 7] [ EMERG] [server] ept rpmsg-sensor
[    0.000000] [ 7] [ EMERG] [server] ept rpmsg-ping
[    0.000000] [ 7] [ EMERG] [server] rpmsg_port queue RX: {used: 0, avail: 8}
[    0.000000] [ 7] [ EMERG] [server] rpmsg buffer list:
[    0.000000] [ 7] [ EMERG] [server] rpmsg_port queue TX: {used: 0, avail: 8}
[    0.000000] [ 7] [ EMERG] [server] rpmsg buffer list:
server> 
server>

@github-actions github-actions bot added Area: Drivers Drivers issues Size: M The size of the change in this PR is medium labels Jan 20, 2026
@CV-Bowen
Copy link
Contributor Author

@xiaoxiang781216 @jerpelea @acassis Could you help review this PR?

Copy link
Contributor

@acassis acassis left a comment

Choose a reason for hiding this comment

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

@CV-Bowen please include a Documentation about RPMsg and VirtIO

We have only some scattered and an empty reference, see:

https://nuttx.apache.org/docs/latest/components/filesystem/rpmsgfs.html
https://nuttx.apache.org/docs/latest/components/drivers/special/virtio.html

@CV-Bowen
Copy link
Contributor Author

@acassis Rpmsg is a big frameworks, which include: rpmsg frameworks, rpmsg services, rpmsg transport, I already added the rpmsg core document in this PR and later I will improve it step by step.

@github-actions github-actions bot added Area: Documentation Improvements or additions to documentation Size: L The size of the change in this PR is large labels Jan 21, 2026
implement the pm feature in rpmsg virtio common part, now the rpmsg
virtio can use in the low power case.

Signed-off-by: Bowen Wang <wangbowen6@xiaomi.com>
Add a concise RPMsg documentation covering:
- Overview of RPMsg framework for AMP systems
- Application scenarios (heterogeneous/homogeneous AMP)
- Layered architecture (Services/Framework/Transport/Physical)
- Message encapsulation process
- Workflow: channel establishment, sending and receiving
- Key design considerations (FIFO order, callback blocking)
- Transport layer comparison

All diagrams use ASCII art for portability.

Signed-off-by: Bowen Wang <wangbowen6@xiaomi.com>
@acassis
Copy link
Contributor

acassis commented Jan 21, 2026

@acassis Rpmsg is a big frameworks, which include: rpmsg frameworks, rpmsg services, rpmsg transport, I already added the rpmsg core document in this PR and later I will improve it step by step.

It is perfect! It is better to have small increments in our Documentation. In the future someone will contribute to other parts and will ask them to document it was well.

@xiaoxiang781216 xiaoxiang781216 merged commit baba361 into apache:master Jan 21, 2026
41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Documentation Improvements or additions to documentation Area: Drivers Drivers issues Size: L The size of the change in this PR is large Size: M The size of the change in this PR is medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants