"In het verleden behaalde resultaten bieden geen garanties voor de toekomst"

These are the ramblings of Matthijs Kooijman, concerning the software he hacks on, hobbies he has and occasionally his personal life.

Questions? Praise? Blame? Feel free to contact me.

My old blog (pre-2006) is also still available.

Sun Mon Tue Wed Thu Fri Sat

15

Tag Cloud
&
(With plugins: config, extensionless, hide, tagging, Markdown, macros, breadcrumbs, calendar, directorybrowse, entries_index, feedback, flavourdir, include, interpolate_fancy, listplugins, menu, pagetype, preview, seemore, storynum, storytitle, writeback_recent, moreentries)
Valid XHTML 1.0 Strict & CSS
Undervolting your AMD PowerNow notebook using Linux

I've previously mentioned that I've undervolted my MSI Megabook S270 notebook. I got a request about how exactly I did this, so I'll elaborate here.

# Background

Undervolting is modifying your hardware parameters in such a way, that the system CPU runs on a lower voltage that it is supposed to. Running on a lower voltage means the CPU uses less power and produces less heat, which are both wanted on a mobile system. Different laptops have different methods of undervolting. What I describe here should applies to AMD Turion64 processors (Which I have), but should also work for all other AMD processors with PowerNow support.

## PowerNow & cpufreq

AMD PowerNow is AMD's technology for scaling CPU frequencies and voltages. How exactly the scaling itself is performed is not all that interesting, how to control it is. Linux has a special cpufreq driver for PowerNow processors, which exports its interface through /sys/devices/system/cpu/cpu0/cpufreq. Here you can select a governor which decides at what speed your CPU should run.

Hidden from the cpufreq interface (which only concerns CPU speed changes), the PowerNow driver also changes the CPU voltage when the speed changes. So, your CPU voltage is already automatically decreased whenever the CPU speed is lowered. Yet, we want to decrease it even further.

# ACPI

Since we cannot set the CPU voltage when scaling, only the frequency, how does PowerNow know what voltage to set? You might think that the CPU itself handles this, but fortunately this is not so. The PowerNow driver gets the information about the possible states and corresponding voltages from the system itself, through one of two means: ACPI and legacy BIOS.

The preferred way of retrieving this information is through ACPI and this might or might not work. For me, this didn't work (There were errors in my kernel logs with CONFIG_CPU_FREQ_DEBUG enabled). When ACPI does not work, the PowerNow driver uses some legacy BIOS call I don't fully understand to get its values.

So, we want to modify the voltage values the PowerNow driver finds. Since I didn't fully know how the BIOS thing worked, that wasn't the way to go. So I had two options:

1. Hack/hardcode the voltage settings in my kernel
2. Fix my ACPI and modify my ACPI table.

I settled for the last one, since that is nicer and a lot better when upgrading kernels.

## Fixing ACPI

Some poking around with the kernel and its debug output, I found that the ACPI object (CPU1._PSS) holding the PowerNow information was not properly loaded by the kernel. Doing the decompile-and-recompile-with-Intel's-compiler trick, showed that the Intel ACPI compiler didn't like that _PSS ACPI object either. See my older post about how I fixed these compilation errors. After fixing these, the PowerNow driver properly gets its settings from ACPI.

With CONFIG_CPU_FREQ_DEBUG enabled, PowerNow properly reports the found settings (don't know if this was any different before fixing ACPI, I don't want to break my ACPI and reboot to find out).

powernow-k8: Found 1 AMD Athlon 64 / Opteron processors (version 1.50.4)
powernow-k8:    0 : fid 0x8, vid 0xa
powernow-k8:    1 : fid 0x0, vid 0x1c
powernow-k8:    0 : fid 0x8 (1600 MHz), vid 0xa (1300 mV)
powernow-k8:    1 : fid 0x0 (800 MHz), vid 0x16 (1000 mV)
powernow-k8: cpu0, init lo 0x808, hi 0x1
powernow-k8: policy current frequency 1600000 kHz
cpu_init done, current fid 0x8, vid 0x8


Part of fixing the ACPI table, is recompiling a fixed version and inserting it into the kernel source. Now, instead of getting the ACPI table from the system on startup, Linux uses your modified table. This means we can modify any value in the table as if the actual ACPI table was changed.

## Tweaking PowerNow

Time to turn to find out how to read the ACPI table and find out which value to actually change. After searching a lot I found the "BIOS and kernel developers guide for Athlon 64 and Opteron". At page 278 they describe where PowerNow gets its information. From there I find that the CPU1._PSS ACPI Package contains a number of (unnamed) packages, one for every CPU State (Two in my case). Each packets contains 6 32bits numbers, which represent various settings. This is my original _PSS Package:

Name (_PSS, Package (0x02)
{
Package (0x06)
{
0x00000640,
0x000055F0,
0x00000064,
0x00000007,
0xE0202A88,
0x00000288
},

Package (0x06)
{
0x00000320,
0x00001EDC,
0x00000064,
0x00000007,
0xE0202D80,
0x00000580
}
})


From the PowerNow specs we learn that every CPU state has a fid and vid, for Frequency ID and Voltage ID respectively. The frequency is calculated as 800 + fid * 100 (in MHz). The voltage is calculated as 1550 - vid * 25 (in mV). This means the frequency cannot go below 800MHz, and since the maximum vid value is 0x1e the minimum voltage is 800mV. I seem to vaguely remember that either the fid or vid can only be set to multiples of 2, yet I can't seem to find any hint of that in the specs now. I did find that the maximum supported frequency change in one go is 200MHz, but the kernel takes care of that, so we don't need to worry about this.

The actual vid is coded into the fifth value in the package, at bits 6-10 (Powernow specs page 280). This means you can increment the fifth value by 0x80 to decrease the voltage by 50mV. Below is the package from the ACPI table I use now, along with a few other examples of different voltages (// denotes a comment).

Package (0x06)
{
0x00000320,
0x00001EDC,
0x00000064,
0x00000007,
//0xE0202D80, // 1000mV
//0xE0202E80,  // 900 mV
0xE0202F00,  // 850 mV
//0xE0202F80,  // 800 mV
0x00000580
}


I've tried running as low as 800mV, but then my system seems to boot okay, but as soon as I login (type my password correctly), it powers off. This seems so predictable that you would suspect the voltage change to have this effect, but increasing the voltage back to 850 mV gives me a stable system that is slightly cooler and uses less power. I'll repeat the (very rough) benchmarks I made back then here (current values are for the entire system).

• 800MHz, 800mV - Crash on startup
• 800MHz, 850mV - ~980mA/39°C idle, ~1170mA/48°C load
• 800MHz, 1000mV - ~1020mA/41°C idle, ~1330mA/50°C load

As you can see, the power savings are very little when the CPU is idle, but quite significant when the CPU gets busy (100% load, though still at 800MHz). I have so for only undervolted my 800MHz state, since I barely ever need all my 1600MHz. But since my CPU gets especially power hungry when it's really fully loaded at 1600MHz (up to 2500mA), I suspect that a lot of power can be saved here. If you try this and get it to work, do tell! And don't forget to mention the actual voltage you get it to run on.

Update: Youri Matthys has been experimenting with undervolting too, and has managed to make his Turion at 1600Mhz run on 1000mV instead of the default 1300mV. The power savings are even better then I'd have hoped for: Under full load the battery usage drops from around 2500mA to 1700mA.

Chris wrote at 2006-06-29 13:13

Hi,

I also want to change the vid for each fid for my HP NX6125 as powernow reports them way too high. So lowering them is my goal. I extracted the DSDT and opened the file. Unfortunately I can´t find any PSS fields

Do you have any ideas, links, ... which could help ?

Matthijs Kooijman wrote at 2006-06-29 19:42

I presume you mean lowering the voltage (since lowering the vid raises the voltage)?

You could perhaps try creating the PSS section yourself, but you should find out what all the other values mean and be really sure you get them right...

I would suggest you try to hack powernow-k8.c, find the section that reads the vids and hardcode them there (requires some coding, though).

newhren wrote at 2006-10-03 21:48

when you change the fith line in a PSS package ("control" filed, which changes VID/FID and a few other parameters), you have to change the sixth line accordingly ("status" field). See page 284 of AMD publication 26094.

Matthijs Kooijman wrote at 2006-10-03 23:31

Hmm, seems you are indeed right. Still, I've been running with my modified ACPI table for more than half a year now, so apparently leaving the status field unmodified is not critical. Perhaps the powernow driver does not use it?

Anyway, the publication you mention is here.

D3LLF wrote at 2006-10-06 00:20

For mobile platform (i'm using Sempron 3200+ on Socket S1) you can as low (or maybe lower?) as:

825mV on 4xfid (800 MHz);

850mV on 5xfid (1000 MHz);

900mV on 6xfid (1200 MHz);

975mV on 7xfid (1400 MHz);

1075mV on 8xfid (1600 MHz).

Yes. You can change the voltage by 25mV not only 50mV (AFAIR dependent on chip core). Under these values my system becomes unstable. If someone is looking for stable voltages he must to check these on his own, because stability can be dependent on individual chip preferences (not only in same model, but individual piece!).

Matthijs Kooijman wrote at 2006-10-06 11:56

D3LLF, does your sempron run at those frequencies out of the box? Or did you manually add them? From what I understood from the specs, if the lowest frequency is 800Mhz, the next frequency can only be 1400Mhz or 1600Mhz, so 800/1000/1200/etc as you describe should not be possible?

newhren wrote at 2006-10-14 22:38

the same AMD doc with K8 specs, mentioned earlier, says that direct freq change is possible only if VCO frequencies differ by no more than 200MHz, and VCO(1600MHz)=1600MHz, VCO(1400MHz)=2800MHz, VCO(1200MHz)=2400MHz, VCO(1000MHz)=2000MHz. So, the only possible freq transition on this Sempron would be 800MHz<->1600MHz.

However, from RMClock forums I learned that such rescrictions are only recomendations from AMD. Theoreticaly, you can make any freq transitions. But if you want to have a stable system, you will need to increase frequency and voltage stablilization times (encoded in the other bits of the fith line in a PSS package). But who knows what would be the right values?

I guess AMD enginieers know their processors a little better than we do, and decided to restrict freq transitions only to the cases than VCO changes by no more than 200MHz for a reason. May be the stablilization times are so high that they eat all benefits of additional P-states, or such "big" transition do some damage to the CPU?

Anyway, here wejp.k.vu/projects/howto_cnq_athlon_64_x2 is a link to a page which describes almost the same process (modifies DSDT to undervolt/overclock K8 a processor).

Docunext wrote at 2007-03-21 12:49

I'm trying to get the Turion 64 voltage right, do you have any other info on that?

antiplex wrote at 2007-04-08 17:28

hi everybody!

i've been trying around with undervolting my amd athlon 64 (desktop) and turion 64 (laptop - also msi's s270) under linux for some time now but haven't come to any satisfying result so far =( . regular speedstepping works fine on both computers under linux but i know from using rmclock (great tool btw!) under win xp that i can go for 800Mhz as a lowest freq with only 850mV on the athlon 64 machine and 925mV on the turion without ever having stability issues and also some higher freq's left enough room for saving some energy -> reducing cpu-temp -> reducing noise (-> providing longer runtimes on the notebook).

i've been able to fix my dsdt acpi tables thanks to this great article here, but since compiling (&running) a new kernel breaks plenty of other modules/drivers on my system and i haven't figured out how to get this working fine yet, i am stuck with this issue. i tried to inject the fixed dsdt into the initramfs and dmesg shows that this works successfully, but the vids (and fids as well if i try to change them) seem not to get used at all, so i guess the need to really get compiled into the kernel.

can anybody confirm this?

furthermore, it seems that it is impossible to add more states to the dsdt. you can increase the package size of the _PSS package so the dsdt gets compiles correctly but then the powernow-k8 section shown by using dmesg will claim that there are too many p-states. did anybody here find a workaround for this?

again, i've been using rmclock for years now and have added some p-states, even with VCO-changes differing from 200MHz without observing any instability-issues or system-damage, so i guess the recomendations in the amd-specs can be ignored, at least for these cpu's.

hopefully, the developers of the linux-phc patch/tool will include support for the powernow-k8 driver as they announce it on their website (www.dedigentoo.org/trac/linux-phc/) and release the upcoming version 0.3.0 soon ...

Comments are closed for this story.