CPUFREQ(4)
π CPUFREQ π
okay bestie, welcome to cpufreq(4), from the Kernel Interfaces Manual β it's the CPU frequency control framework and it's literally the main character of power management, no cap. π
π NAME π
cpufreq β CPU frequency control framework β¨
πΈ SYNOPSIS πΈ
device cpufreq
#include <sys/cpu.h>
int
cpufreq_levels(device_t dev, struct cf_level *levels, int *count);
int
cpufreq_set(device_t dev, const struct cf_level *level, int priority);
int
cpufreq_get(device_t dev, struct cf_level *level);
int
cpufreq_drv_settings(device_t dev, struct cf_setting *sets, int *count);
int
cpufreq_drv_type(device_t dev, int *type);
int
cpufreq_drv_set(device_t dev, const struct cf_setting *set);
int
cpufreq_drv_get(device_t dev, struct cf_setting *set);
π¦ DESCRIPTION π¦
So the cpufreq driver is giving unified kernel + user interface for CPU frequency control drivers, and honestly? iconic. π
It takes multiple drivers that each offer different settings and smushes them together into one single interface of all possible levels β like a group chat for frequency settings, except everyone actually gets along.
You can reach this interface in two ways, bestie:
- directly via
sysctl(8)π - or by telling
/etc/rc.d/power_profilethat it should switch settings whenever the AC line state changes, viarc.conf(5)π
β SYSCTL VARIABLES β
quick heads up before we dive in: these settings may be overridden by kernel drivers that are requesting alternate settings. And when that happens? the original values get restored once the condition has passed (think: the system has cooled down enough, she's fine now π§). And if a sysctl can't be set because of an override condition, it returns EPERM. rude but valid.
π IMPORTANT: the frequency cannot be changed if TSC is in use as the timecounter. Why? because the timecounter system needs a source with a constant rate, periodt. You can switch the timecounter source with thekern.timecounter.hardwaresysctl, and the available modes live in thekern.timecounter.choicesysctl entry. go look, iykyk.
here's the whole roster π«Ά:
dev.cpu.%d.freqβ current active CPU frequency, in MHz. the now-now.dev.cpu.%d.freq_levelsβ the levels currently available for the CPU, shown as frequency/power usage. values are in units of MHz and milliwatts. β¨dev.DEVICE.%d.freq_settingsβ the settings currently available for the driver, also frequency/power usage, also MHz and milliwatts. this one is super helpful for figuring out which settings are offered by which driver β debugging queen behavior ππdebug.cpufreq.lowestβ the lowest CPU frequency, in MHz, to offer to users. this setting is also reachable via a tunable with the same name. use it to disable those very low levels that may be unusable on some systems πdebug.cpufreq.verboseβ print verbose messages. also accessible via a tunable with the same name. she's chatty π¬
π₯ SUPPORTED DRIVERS π₯
absolute frequency control
these device drivers offer absolute frequency control through the cpufreq interface. usually only one of them can be active at a time, so no drama:
acpi_perfβ ACPI CPU performance statesestβ Intel Enhanced SpeedStepichssβ Intel SpeedStep for ICHpowernowβ AMD PowerNow! and Cool'n'Quiet for K7 and K8smistβ Intel SMI-based SpeedStep for PIIX4
relative frequency control
these ones offer relative frequency control and have an additive effect (they stack, bestie, they're a team π):
acpi_throttleβ ACPI CPU throttlingp4tccβ Pentium 4 Thermal Control Circuitry
π KERNEL INTERFACE π
kernel components can query and set CPU frequencies through the cpufreq kernel interface. the whole ritual goes like this:
- obtain a
cpufreqdevice - call
cpufreq_levels()to get the currently available frequency levels - check the current level with
cpufreq_get() - set a new one from the list with
cpufreq_set()
each level may actually reference more than one cpufreq driver β but kernel components do not need to be aware of that, bless. the total_set element of struct cf_level gives you a summary of the frequency and power for that level. unknown or irrelevant values are set to CPUFREQ_VAL_UNKNOWN. π«₯
cpufreq_levels()
takes a cpufreq device and an empty array of levels. the count value should be set to the number of levels available, and once the function completes it'll be set to the actual number of levels returned. if there are more levels than count will allow? it should return E2BIG. too much, she said. π
cpufreq_get()
takes a pointer to space where a level can be stored. after a successful completion, the output is the current active level β and it's equal to one of the levels that cpufreq_levels() returned. matching, as she should. β¨
cpufreq_set()
takes a pointer to a level and attempts to activate it. the priority (i.e., CPUFREQ_PRIO_KERN) tells cpufreq whether to override previous settings while activating this level.
- if
priorityis higher than the current active level, that level gets saved and overridden with the new level πΎ - if a level is already saved, the new level is set without overwriting the older saved level
- if
cpufreq_set()is called with aNULLlevel, the saved level gets restored π«Ά - if there's no saved level,
cpufreq_set()returnsENXIO - if
priorityis lower than the current active level's priority, this method returnsEPERM
π DRIVER INTERFACE π
kernel drivers that offer hardware-specific CPU frequency control export their individual settings through the cpufreq driver interface. to do that, they implement these methods: cpufreq_drv_settings(), cpufreq_drv_type(), cpufreq_drv_set(), and cpufreq_drv_get(). on top of that, the driver must attach a device as a child of a CPU device so that the cpufreq framework can call these methods. no attaching, no calling, that's the rule π
cpufreq_drv_settings()
returns an array of currently available settings, each one of type struct cf_setting. the driver should set unknown or irrelevant values to CPUFREQ_VAL_UNKNOWN. all of the following elements for each setting should be returned:
struct cf_setting {
int freq; /* CPU clock in MHz or 100ths of a percent. */
int volts; /* Voltage in mV. */
int power; /* Power consumed in mW. */
int lat; /* Transition latency in us. */
device_t dev; /* Driver providing this setting. */
};
on entry to this method, count contains the number of settings that can be returned. on successful completion, the driver sets it to the actual number of settings returned. if the driver offers more settings than count will allow, it should return E2BIG. (again. she's overflowing. π)
cpufreq_drv_type()
indicates the type of settings the driver offers β either CPUFREQ_TYPE_ABSOLUTE or CPUFREQ_TYPE_RELATIVE. additionally, the driver may set the CPUFREQ_FLAG_INFO_ONLY flag if the settings it provides are information for other drivers only and cannot be passed to cpufreq_drv_set() to activate them. look, don't touch, got it π
ββοΈ
cpufreq_drv_set()
takes a driver setting and makes it active. if the setting is invalid or not currently available, it should return EINVAL. bestie said no. π«
cpufreq_drv_get()
returns the currently-active driver setting. the struct cf_setting returned must be valid for passing to cpufreq_drv_set(), and that includes all elements being filled out correctly. if the driver cannot infer the current setting β even by estimating it with cpu_est_clockrate() β then it should set all elements to CPUFREQ_VAL_UNKNOWN. shrug emoji, we tried. π€·ββοΈ
π SEE ALSO π
acpi(4), est(4), timecounters(4), powerd(8), sysctl(8)
π AUTHORS π
- Nate Lawson
- Bruno Ducrot contributed the
powernowdriver. π«‘
π BUGS π
the tea, and it's lukewarm:
- the following drivers have not yet been converted to the
cpufreqinterface:longrun(4). girl is still stuck in the old era π - notification of CPU and bus frequency changes is not implemented yet. she doesn't text back. π΅
- when multiple CPUs offer frequency control, they cannot be set to different levels and must all offer the same frequency settings. matching outfits only, no exceptions π―ββοΈ
and that's the whole page, bestie π this was the cpufreq(4) manual from Debian, dated March 3, 2006 β yes she's vintage and she still ate π
stay cool, stay clocked, and go touch some sysctl β¨π¦π
π¦ where this page comes from
- debian bookworm: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- debian trixie: freebsd-manpages 12.2-2 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu jammy: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu noble: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu questing: freebsd-manpages 12.2-2
- ubuntu resolute: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu stonking: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- Copyright (c) 2005 Nate Lawson
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms