Linux kernel undervolting patch for AMD processors
Simple patch for 2.6.27 Linux kernel to provide full control over voltages/frequencies of AMD CPUs supporting Cool’n’Quiet technology.
Update: patches for 2.6.31 and 2.6.32 are available too.
Update 2010/02/10: it was pointed out that Linux-PHC project currently provides patches for AMD (see comments for details), so I’d strongly recommend checking their patches first instead of mine.
When assembling my home server back in 2007 spring one of the key requirements was to support near-silent operation. The whole setup is beyond the scope of this article, but one of the tasks I had to solve was to lower the power CPU uses, so that I can use passive cooling.
Getting mobile CPU or CPU with reduced TDP was not an option due to their cost and unavailability, so I bought just normal AMD Sempron CPU with standard TDP, and reduced the voltages CPU runs at to decrease CPU power usage. It should be noted that the power CPU dissipates is squarely proportional to the voltage CPU uses, so even slight decrease in voltage might produce quite noticeable difference in power.
As the server was intended only for very modest use (= most of the time it runs idle) the other important requirement was that CPU supports frequency/voltage scaling (which AMD called PowerNow! first and then changed it to Cool’n’Quiet), so that CPU remains on its lowest frequency/voltage most of the time and starts to consume power only when load is sufficiently high.
However, at that time I was not able to find any reasonable solution that would allow me to perform the undervolting on Linux, especially considering I needed Cool’n’Quiet support, so voltages should be reduced not once and for fixed frequency, but the whole voltage table should be changed.
I’ve found Linux PHC project, which supported undervolting for Intel CPUs, but they did not have AMD support - they’ve claimed they have it working, but not ready for release yet.
To keep the story short: I took the patch from Linux PHC project for Intel CPUs and adapted it for powernow-k8 driver in Linux, which at that time was somewhere near 2.6.21 version, if I remember correctly. I expected it to be “temporary hack” only, until Linux PHC releases “proper” patch, so I haven’t published it at that time.
However, 1.5 years later, it seems there’s still no progress in the direction of AMD patch; besides that, for all previous kernel upgrades I’ve just copied the same patched powernow-k8.c/.h files over current kernel implementation (so, in fact downgrading powernow-k8 driver to the patched version of 2.6.21 kernel I had), but recently for 2.6.27 upgrade I’ve ported the patch to the new driver version - and, after doing that, decided that it might be useful to publish it - just in case anyone else has the same problem to solve
Well, I hope you understand what you’re doing, if not - STOP NOW!
Also note that the patch was meant to be “temporary hack”, with all the consequences it has
powernow-k8.c driver patch for undervolting support for linux-2.6.27 kernel series, 2.20.0 powernow-k8 driver version.
Just patch your kernel & recompile it.
Either pass modified voltages & frequencies list on kernel command line at boot or print it to the /sys/devices/system/cpu/cpu0/cpufreq/voltage_table control file on sysfs.
Examples for my setup are below:
- Command line:
echo 1800000:1050,1600000:1000,800000:875 > /sys/devices/system/cpu/cpu0/cpufreq/voltage_table
Note that when you pass these options in kernel command line, you are not forced to use exactly the frequencies your CPU is initially designed for: for example, my AMD Sempron CPU is meant to work with frequencies 1.0 GHz and 1.8 GHz in Cool’n’Quiet mode, but I successfully use frequencies 0.8 GHz, 1.6 GHz and 1.8 GHz, which allows me to run it in idle mode at lower frequency and lower voltage than if I would use default 1.0 GHz frequency.
Note, however, that frequencies choice is not arbitrary: you’re advised to read AMD documentation to understand which frequencies can be specified and which cannot, particularly you should understand “high” and “low” states concept.
I’m not 100% sure (as quite some time passed since then), but if I remember correctly changing frequencies after powernow-k8 driver is initialized is not supported, as cpufreq has already initialized its own structures which depend on frequencies and will screw up if things are changed after initialization.
Finding optimal voltages may be quite tedious and long process. While not being expert, I recommend using similar practices as to what overclockers use to find optimal values: i.e. start with default values and then gradually change them in small steps, each time checking thoroughly your system for stability.
All voltages should be multiple of 0.025 V and lie in the range 0.8 V - 1.55 V, but of course you should also use your common sense and not try to apply 1.55 V at 0.8 GHz or 0.8 V at 2.6 GHz
Note that it might be a good idea to find first optimal voltages for every frequency separately by locking one particular frequency using
/sys/devices/system/cpu/cpu0/cpufreq/* interface, and after voltages for all frequencies are known - test system in actual mode you’re going to use it, for example with “ondemand” governor or whatever.
One more observation: changing voltages too sharply might sometimes lead to system freezes & other failures. For example, changing voltage from 1.4 V (if I remember correctly, that’s the default voltage for my CPU on 1.8 GHz frequency) to 1.05 V (which is the optimal value found experimentally) causes system freezes in almost half of the cases, so I perform gradual transition instead by setting 1.15 V at kernel command line and later correcting it to 1.05 V during the boot sequence.
- Current implementation is not tested on fully ACPI-compliant motherboards/BIOSes: the only system it was tested on is certainly not, so I have no clue if it works correctly on these systems or not.
- I haven’t tested it with sysfs or ACPI options turned off in kernel config - so I’m not sure if it compiles at all with these options, and if yes - whether it works or not.
- In fact, though I’ve used it for undervolting, nobody forbids you to use it for overclocking also.
- Instead of patching powernow-k8.c you might also consider changing your ACPI table so that it contains the values you want: Linux kernel allows you to override the needed part of ACPI table at boot with custom values. In my case it was not an option because I needed transition to happen in two steps, and also my original BIOS is not enough ACPI-compliant, so I didn’t want to risk by experimenting with that - but in other situations it might be quite reasonable alternative.