[RFC] drivers/cpufreq: Add a CPU frequency scaling framework. - #19737
[RFC] drivers/cpufreq: Add a CPU frequency scaling framework.#19737Fishwaldo wants to merge 3 commits into
Conversation
The tree has carried consumers of a cpufreq framework for two years without the framework. thermal_cpufreq_cooling.c includes nuttx/cpufreq.h and speaks of policies and QoS requests; thermal_dummy.c defines a whole lower half and calls cpufreq_init; both sit behind THERMAL_CDEV_CPUFREQ and THERMAL_DUMMY_CPUFREQ, whose dependency on CPUFREQ no configuration could ever satisfy. The API they were written against is therefore already fixed, down to the order of the driver's operations and the detail that a policy can be cast to reach its driver, and this supplies the missing half to that exact contract rather than inventing a new one. The shape is one policy arbitrated by windows. A platform provides a lower half: an ascending frequency table and a way to move between its entries. Each requester (a thermal cooling device, an application, a power manager) installs a request naming the window it can live with, and the resolved frequency is the highest table entry under the lowest ceiling. Speed is the default; any one requester can cap it; when requests collide the lowest ceiling wins. The lower half only ever hears "go to entry N" and never learns who wanted what. With CPUFREQ_CHARDEV the policy is also /dev/cpufreq, with ioctls to read the current frequency, list the table, and install a request. Each open descriptor owns at most one request, released on close, including on task exit. Suspend and resume pass through to the lower half; while suspended the resolver leaves the hardware alone and applies whatever changed on the way back. Verified on hardware against both existing consumers: with THERMAL_DUMMY and its cpufreq half enabled, the dummy zone's simulated temperature drives the previously dead cooling device, which installs and updates QoS requests through this framework onto the dummy lower half. /proc/thermal showing the cpufreq cooling device stepping its state is upstream's own two-year-old code running for the first time. Assisted-by: Claude:claude-opus-5 Signed-off-by: Justin Hammond <justin@dynam.ac>
The file calls therr and thinfo, which live in nuttx/debug.h via debug.h, and included neither. It has never been compilable, since its Kconfig option depends on a CPUFREQ symbol that did not exist, so nobody ever saw the error. With the cpufreq framework now present the option is satisfiable and the missing include is the only thing between this file and working, two years after it was merged. Assisted-by: Claude:claude-opus-5 Signed-off-by: Justin Hammond <justin@dynam.ac>
The cpufreq framework had no documentation. This covers what a platform must provide, how competing requests resolve into one frequency, the in-kernel QoS calls, the /dev/cpufreq ioctls, and how the thermal cooling device sits on top of it. Two properties of the resolver are stated explicitly rather than left to be discovered, since both are deliberate: a floor never raises the frequency, because the resolver already picks the highest permitted table entry; and where windows do not intersect the lowest ceiling wins. Assisted-by: Claude:claude-opus-5 Signed-off-by: Justin Hammond <justin@dynam.ac>
| # ############################################################################## | ||
|
|
||
| if(CONFIG_CPUFREQ) | ||
| target_sources(drivers PRIVATE cpufreq.c) |
There was a problem hiding this comment.
it's better to integrate the well test and more functionality from:
https://github.com/open-vela/nuttx/tree/dev/drivers/devfreq
Instead rewrite from scratch by AI.
BTW, it the origin cpufreq framework work with thermal framework directly and extend to support any device frequency scaling.
|
You should start this discussion on the mailing list please @Fishwaldo |
Agree, I think both implementations could be merged in a single subsystem |
|
Closing this RFC. The devfreq framework has since landed on master (#19741), and that is the Thanks to everyone who looked at it. |
Hi @Fishwaldo thank you very much for your initial cpufreq proposal. This is sad when things like that happen, but Xiaomi has many drivers and features implemented in their open-vela/NuttX fork and they don't have time or enough developers to submit it upstream. So, if we have added your solution they will spend a lot of time and money re-validating everything and they have million of devices on street that will need to be updated as well. I'm glad that you understand it and didn't get upset. |
This is an RFC. The code is complete and tested on hardware, but it adds a
new subsystem with a public header, so I would rather have agreement on the
design than merge it and discover the API is wrong. Specific questions are at
the end. Happy to rework any of it.
Summary
without the framework.
drivers/thermal/thermal_cpufreq_cooling.cincludes
nuttx/cpufreq.hand speaks of policies and QoS requests;thermal_dummy.cdefines a whole lower half and callscpufreq_init().Both sit behind
THERMAL_CDEV_CPUFREQandTHERMAL_DUMMY_CPUFREQ, whosedependency on
CPUFREQno configuration could ever satisfy.to the order of the driver's operations and the detail that a policy can
be cast to reach its driver. This supplies the missing half to that exact
contract rather than inventing a new one.
ascending frequency table and a way to move between its entries. Each
requester (a thermal cooling device, an application holding
/dev/cpufreq, a power manager) installs a[min, max]window. Theresolved frequency is the highest table entry at or below the lowest
ceiling. Speed is the default; any one requester can cap it; when windows
do not intersect the lowest ceiling wins. The lower half only ever hears
"go to table entry N".
CPUFREQ_CHARDEVthe policy is also/dev/cpufreq, with ioctls toread the current frequency, list the table, and install a request. Each
open descriptor owns at most one request, released on close, including on
task exit.
resolver leaves the hardware alone and applies whatever changed on the way
back.
Documentation/components/drivers/special/cpufreq.rst.Questions for reviewers
one, globally, because that is what the existing consumers assume
(
cpufreq_policy_get()takes no argument). Fine for now, or should theAPI carry a policy handle from the start? Adding one later is a break.
minis structurally inert. The resolver picks the highest entry underthe lowest ceiling, which is already the maximum permitted, so a floor is
either already satisfied or can only be met by violating a ceiling. It is
accepted and stored, never read. I left it because the existing thermal
consumer passes it and because a future governor that selects below maximum
would make it meaningful. Keep it, keep it but reject inverted windows with
-EINVAL, or drop it from the API?capped". No ondemand, no schedutil, no idle-driven scaling. Is that the
right default for NuttX, or should there be a governor hook now?
/dev/cpufreqwith four ioctls. thermal exposes/proc/thermalfor inspection; cpufreq has no procfs equivalent, so thereis no way to see the installed requests. Worth adding?
and what this port uses, but nothing enforces it, and mixing units across
consumers of one policy would be silently wrong. Fix it as kHz in the API?
drivermust be the first member ofstruct cpufreq_policy, becausethermal_cpufreq_cooling.ccasts a policy pointer to reach the lower half.That is an unenforced ABI constraint I have documented rather than fixed.
Leave it, or add an accessor and change that caller?
Impact
two existing but unbuildable features reachable.
CONFIG_CPUFREQdefaults off.lower half.
drivers, plus Kconfig help.
/dev/cpufreqgrants no more than the abilityto cap the CPU's speed, and a request dies with its descriptor.
Testing
I confirm that changes are verified on local setup and works as intended:
15.2.0
(downstream board port, not yet upstream), kernel build, with a real
lower half over the SoC's CPU PLL and a real die temperature sensor
sphinx-buildclean, no warnings from the new pageBoth existing consumers were driven, which is the point of the exercise.
First,
THERMAL_DUMMYwith its cpufreq half enabled. The dummy zone'ssimulated temperature drives the previously dead cooling device, which
installs and updates QoS requests through this framework:
Then the real thing: the board's own die zone, throttling actual silicon as
it heats and releasing as it cools.
c:cpufreq s:Nis the cooling state.A userspace floor held through
/dev/cpufreq, which also demonstratesquestion 2 above: the request is accepted and the frequency stays at the
top entry, because that is where it already was.
/proc/thermalshowing the cpufreq cooling device stepping its state isupstream's own two-year-old code running for the first time.
PR verification Self-Check
Claude (claude-opus-5) assisted with authoring this framework, its code
comments, the documentation and this PR description. The commits carry
Assisted-by:tags per CONTRIBUTING.md §1.5.