zzby0 opened a new pull request, #19741:
URL: https://github.com/apache/nuttx/pull/19741
## Summary
This PR introduces a **device frequency scaling (devfreq) framework** for
NuttX, providing generic dynamic voltage and frequency scaling (DVFS)
infrastructure for any clock-scalable device (CPU, GPU, memory bus, DSP,
etc.).
Unlike a single system-wide CPU policy, devfreq manages any number of
independent devices, each registered by name with its own frequency table and
governor.
**Architecture** — the framework separates policy from mechanism:
- A **lower half** (`struct devfreq_driver_s`) is provided by the platform:
an
ascending frequency table plus `target_index`/`get_frequency` callbacks.
The
lower half is only ever told "go to table entry N".
- Two independent forces resolve the frequency:
- **QoS requests** — each requester installs a `[min, max]` window; the
framework aggregates all windows (highest `min`, lowest `max`) into a
single
clamp. When windows do not intersect, the driver's `conflict_policy`
(`PREFER_HIGH` / `PREFER_LOW`) decides the winner.
- **Governors** — `performance` (top of window), `powersave` (bottom of
window), and `ondemand` (load-driven scaling).
- The resolved frequency is snapped to a real table entry and applied through
the lower half.
**Components:**
- Core framework (`drivers/devfreq/devfreq.c`) — registration, table
validation, QoS resolution, governor dispatch, suspend/resume, change
notifier chain.
- Governors: `performance`, `powersave`, `ondemand`.
- QoS constraint engine (`devfreq_qos.c`) built on a priority-sorted list
(`include/nuttx/plist.h`).
- procfs interface (`/proc/devfreq/<name>`) — read frequency table / current
frequency / governor / QoS list; write to install a frequency constraint
from user space.
- Public API (`include/nuttx/devfreq.h`) and documentation
(`Documentation/.../special/devfreq.rst`).
## Impact
- **New feature**: adds the devfreq framework. Entirely opt-in — gated behind
`CONFIG_DEVFREQ` (default `n`); no effect on existing configurations.
- **Build**: new `drivers/devfreq/` subsystem wired into `drivers/Kconfig`,
`drivers/Makefile`, and `CMakeLists.txt`.
- **User space**: when `CONFIG_DEVFREQ_PROCFS` is set, exposes
`/proc/devfreq/<name>` (read status/table, write `<min> <max>` in kHz to
constrain, `0 0` to clear). Requires `CONFIG_FS_PROCFS`; auto-selects
`CONFIG_FS_PROCFS_REGISTER`.
- **New config options**: `CONFIG_DEVFREQ`, `CONFIG_DEVFREQ_PROCFS`,
`CONFIG_DEVFREQ_PROCFS_QOS`, `CONFIG_DEVFREQ_GOV_ONDEMAND`,
`CONFIG_DEVFREQ_SAMPLE_RATE`, `CONFIG_DEVFREQ_LOAD_THRESHOLD`.
- **New header**: `include/nuttx/plist.h` (priority-sorted list,
header-only),
a dependency of the QoS engine.
- **Hardware**: no impact unless a platform registers a lower-half driver.
- **Documentation**: new page under
`Documentation/components/drivers/special/`.
- **Compatibility**: no changes to existing APIs; no regressions expected.
## Testing
### Host & Targets
| Item | Detail |
| ------------- | --------------------------------------------------------- |
| Host OS | Linux x86_64 (Ubuntu) |
| Toolchains | host `gcc` 13.4.0 (sim), `arm-none-eabi-gcc` 10.3.1 (arm) |
| NuttX / apps | apache/master |
| Real hardware | BES2800bp, ARMv8-M Cortex-M55 |
`tools/checkpatch.sh` passes on all commits.
### Build Verification
| Arch | Config | devfreq options | Result
|
| ------------- | ------------------ | ---------------------------- |
------------------------ |
| sim (x86_64) | `sim:nsh` | DEVFREQ + PROCFS + PROCFS_QOS | `LD
nuttx` OK, 0 warnings |
| arm (Cortex-A7) | `qemu-armv7a:nsh` | DEVFREQ + PROCFS + PROCFS_QOS | `LD
nuttx` OK, 0 warnings |
### Runtime Functional Test — Simulator
A temporary dummy lower-half driver (table `200000 400000 600000 800000` kHz)
was registered as `/proc/devfreq/test` to exercise the framework end to end
(scaffolding removed after testing).
**performance governor** (selects the top of the resolved window):
```
nsh> cat /proc/devfreq/test
governor: performance
cur_freq: 800000
freq_table: 200000 400000 600000 800000
nsh> echo '0 400000' > /proc/devfreq/test # cap: max=400000
test_devfreq: target_index=1 freq=400000 # -> cur_freq 400000
nsh> echo '600000 800000' > /proc/devfreq/test # floor honoured
test_devfreq: target_index=3 freq=800000 # -> cur_freq 800000
nsh> echo '200000 600000' > /proc/devfreq/test # window [200000,600000]
test_devfreq: target_index=2 freq=600000 # -> top-in-window 600000
nsh> echo '0 0' > /proc/devfreq/test # clear QoS
test_devfreq: target_index=3 freq=800000 # -> restores 800000
nsh> echo '800000 200000' > /proc/devfreq/test # invalid min>max
# -> write returns -EINVAL,
no change
```
**powersave governor** (selects the bottom of the resolved window):
```
nsh> cat /proc/devfreq/test
test_devfreq: target_index=0 freq=200000 # default -> lowest 200000
governor: powersave
cur_freq: 200000
nsh> echo '400000 800000' > /proc/devfreq/test # window [400000,800000]
test_devfreq: target_index=1 freq=400000 # -> bottom-in-window 400000
```
### Runtime Functional Test — Real Hardware (BES2800bp, Cortex-M55)
The framework was also validated on real silicon driving the CPU clock
through
a platform CPU devfreq lower half (`/proc/devfreq/cpu`, table
`32 26000 52000 104000 208000 320000` kHz, performance governor). The
lower-half
CPU driver is board/downstream code and is not part of this PR.
**Scenario 1 — Concurrent QoS requests with conflicting windows.**
Two requests are installed: one caps at `208000`, another pins
`[320000, 320000]`. The windows do not intersect (aggregate min `320000` >
aggregate max `208000`), so the driver's `conflict_policy` resolves it — here
the higher frequency wins and the CPU runs at 320 MHz:
```
ap> cat /proc/devfreq/cpu
devfreq: cpu
governor: performance
cur_freq: 320000
suspended: False
freq_table: 32 26000 52000 104000 208000 320000
qos_list(min, max, backtrace):
0, 208000,
320000, 320000,
```
**Scenario 2 — Updating a QoS request re-resolves and changes the real
clock.**
The `[320000, 320000]` request is updated to `[208000, 208000]` via procfs.
The
windows now intersect at `208000`, and the CPU frequency drops to 208 MHz on
hardware:
```
ap> echo "208000 208000" > /proc/devfreq/cpu
ap> cat /proc/devfreq/cpu
devfreq: cpu
governor: performance
cur_freq: 208000
suspended: False
freq_table: 32 26000 52000 104000 208000 320000
qos_list(min, max, backtrace):
0, 208000,
208000, 208000,
```
### Coverage Summary
Verified across simulator and hardware: device registration, procfs
read/write,
QoS `[min, max]` aggregation (upper cap and lower floor), multi-requester
conflict resolution via `conflict_policy`, governor selection (performance =
top-of-window, powersave = bottom-of-window), QoS clear, invalid-input
rejection, and lower-half `target_index` / `get_frequency` invocation with a
real frequency change on Cortex-M55.
### Documentation
`Documentation/components/drivers/special/devfreq.rst` renders correctly via
`make html`.
### Notes
All temporary test scaffolding (the sim dummy driver) was reverted after
testing and is not part of this PR.
--
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]