markus reichelt, July 2005
v1.1.1, last modified: 2008-04-19, status: actively maintained
This howto is intended for linux users who own a Banias-based centrino system, like the Asus M2NE laptop, and want to maximize battery life by manually adapting CPU speed to their needs.
Modern centrino systems allow to change clock speed and voltage of the CPU. Adapting the CPU frequency to one's needs can result in reduced battery power consumption and lower overall system temperature. There are several tools available to achieve this manually, such as cpuspeedy.
With tools like cpuspeedy, the lowest possible frequency of a Banias-based centrino system is 600 MHz. However, the Banias Datasheet lists voltages adequate for speeds down to 100 Mhz. This howto explains in detail how to set 100, 200, and 400 MHz on a 2.6.7 2.6.21-rc1 2.6.25 kernel, while sustaining system stability. It does not explain how this works, nor how it could be achieved on Dothan-based systems.
A big THANK YOU goes to st3 for writing about this topic on the linux kernel mailing list. I would have lived with 600 MHz CPU speed and poor battery life, if it hadn't been for him ;-)
This document is located at http://mareichelt.de/pub/texts.underclocking.php.
Disclaimer: Proceed at your own risk. I'm not responsible for whatever happens to your system.
[top]
Not much... you'll need the following stuff:
and the editor of your choice to modify the kernel source manually.
We need a Banias CPU to play with, so if you don't know or are unsure about your CPU, use cpuid to indentify it. On my system cpuid prints this info:
CPU:
vendor_id = "GenuineIntel"
version information (1/eax):
processor type = primary processor (0)
family = Intel Pentium Pro/II/III/Celeron, AMD Athlon/Duron,
Cyrix M2, VIA C3 (6)
model = 0x9 (9)
stepping id = 0x5 (5)
extended family = 0x0 (0)
extended model = 0x0 (0)
(simple synth) = Intel Pentium M / Celeron M (Banias B1), .13um
miscellaneous (1/ebx):
process local APIC physical ID = 0x0 (0)
cpu count = 0x0 (0)
CLFLUSH line size = 0x8 (8)
brand index = 0x16 (22)
brand id = 0x16 (22): Intel Pentium M, .13um
feature information (1/edx):
x87 FPU on chip = true
virtual-8086 mode enhancement = true
debugging extensions = true
page size extensions = true
time stamp counter = true
RDMSR and WRMSR support = true
physical address extensions = false
machine check exception = true
CMPXCHG8B inst. = true
APIC on chip = true
SYSENTER and SYSEXIT = true
memory type range registers = true
PTE global bit = true
machine check architecture = true
conditional move/compare instruction = true
page attribute table = true
page size extension = false
processor serial number = false
CLFLUSH instruction = true
debug store = true
thermal monitor and clock ctrl = true
MMX Technology = true
FXSAVE/FXRSTOR = true
SSE extensions = true
SSE2 extensions = true
self snoop = false
hyper-threading / multi-core supported = false
therm. monitor = true
IA64 = false
pending break event = true
feature information (1/ecx):
PNI/SSE3: Prescott New Instructions = false
MONITOR/MWAIT = false
CPL-qualified debug store = false
VMX: virtual machine extensions = false
Enhanced Intel SpeedStep Technology = true
thermal monitor 2 = true
context ID: adaptive or shared L1 data = false
cmpxchg16b available = false
xTPR disable = false
cache and TLB information (2):
0xb0: instruction TLB: 4K, 4-way, 128 entries
0xb3: data TLB: 4K, 4-way, 128 entries
0x02: instruction TLB: 4M pages, 4-way, 2 entries
0x87: L2 cache: 1M, 8-way, 64 byte lines
0x30: L1 cache: 32K, 8-way, 64 byte lines
0x04: data TLB: 4M pages, 4-way, 8 entries
0x2c: L1 data cache: 32K, 8-way, 64 byte lines
extended feature flags (0x80000001/edx):
SYSCALL and SYSRET instructions = false
execution disable = false
64-bit extensions technology available = false
Intel feature flags (0x80000001/ecx):
LAHF/SAHF supported in 64-bit mode = false
brand = " Intel(R) Pentium(R) M processor 1600MHz"
(multi-processing synth): none
(synth) = Intel Pentium M (Banias B1), .13um
As usual the last line is the important one.
[top]
I assume you already have adapted the kernel to your needs, installed it properly and that the system is stable. Additionally, I assume that a recent version of cpuspeedy is installed and working. Now go to the directory where you keep the kernel sources and modify speedstep-centrino.c
dave@hal9000:~/src/linux$ vi arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
and look for the entry listing the speed of your Banias CPU. In this case it's 1.60 GHz, and the correct entry is listed as:
/* Intel Pentium M processor 1.60 GHz (Banias) */
static struct cpufreq_frequency_table banias_1600[] =
{
OP( 600, 956),
OP( 800, 1036),
OP(1000, 1164),
OP(1200, 1276),
OP(1400, 1420),
OP(1600, 1484),
{ .frequency = CPUFREQ_TABLE_END }
};
Now let's have a look at the Banias Datasheet, page 19, "Electrical Specifications", Table 2. Voltage Identification Definition. You'll recognize the numbers 956, 1036, 1164, and so on. That's the Voltage in mV of the given frequency in MHz. So, adding lower frequencies and corresponding voltages to the cpufreq_frequency_table is child's play; just add the following lines just prior to the first OP listing the 600 MHz-entry:
OP( 100, 732), OP( 200, 748), OP( 400, 780),
CAUTION! These values apply to my system, and my system only. It may be that they work on your system, but you will have to take that chance and run tests on your own. I did, and that's just what I came up with; these values are merely listed for reference.
What's left to do is check for relevant kernel config options.
[top]
Let's check necessary kernel .config options, I successfully use the following:
[...] # # CPU Frequency scaling # CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_TABLE=y CONFIG_CPU_FREQ_DEBUG=y CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_STAT_DETAILS=y # CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y # CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y # # CPUFreq processor drivers # # CONFIG_X86_ACPI_CPUFREQ is not set # CONFIG_X86_POWERNOW_K6 is not set # CONFIG_X86_POWERNOW_K7 is not set # CONFIG_X86_POWERNOW_K8 is not set # CONFIG_X86_GX_SUSPMOD is not set CONFIG_X86_SPEEDSTEP_CENTRINO=y # CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI is not set CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE=y CONFIG_X86_SPEEDSTEP_ICH=y CONFIG_X86_SPEEDSTEP_SMI=y # CONFIG_X86_P4_CLOCKMOD is not set # CONFIG_X86_CPUFREQ_NFORCE2 is not set # CONFIG_X86_LONGRUN is not set # CONFIG_X86_LONGHAUL is not set # CONFIG_X86_E_POWERSAVER is not set # # shared options # CONFIG_X86_SPEEDSTEP_LIB=y CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK=y [...]
Running make menuconfig, be sure to follow these instructions:
In CPU Frequency Scaling under Intel Enhanced SpeedStep first toggle Use ACPI tables to decode valid frequency/voltage (deprecated) to be able to toggle Built-in tables for Banias CPUs and after toggling it, disable Use ACPI tables to decode valid frequency/voltage (deprecated) again. Mine looks like this -- unfortunately, it cannot be seen that CONFIG_X86_SPEEDSTEP_CENTRINO_TABLE is enabled, only that CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI is not set. So check your .config to be sure before compiling.
[top]
CAUTION! Don't compute important data while stress-testing; always have a backup handy.
After having compiled, installed, and rebooted the kernel, enter as the superuser root
root@hal9000:~# cpuspeedy --freqs
and you should see the following listing:
100000 KHz (100 MHz) 200000 KHz (200 MHz) 400000 KHz (400 MHz) 600000 KHz (600 MHz) 800000 KHz (800 MHz) 1000000 KHz (1 GHz) 1200000 KHz (1.2 GHz) 1400000 KHz (1.4 GHz) 1600000 KHz (1.6 GHz)
This means that you can use cpuspeedy to set any of the listed frequencies. Since we are interested in 100, 200, and 400 MHz, you start with 100 MHz and see how the system reacts. Enter this as root:
root@hal9000:~# cpuspeedy 100 MHz
and you should see something like this:
cpuspeedy: CPU speed is now 100 MHz (6%) temperature is 42 C
To check that CPU speed really was changed to 100 MHz, let's cat /proc/cpuinfo and watch the bogomips value; it has to differ after CPU speed changes were made.
root@hal9000:~# cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 9
model name : Intel(R) Pentium(R) M processor 1600MHz
stepping : 5
cpu MHz : 100.000
cache size : 1024 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 2
wp : yes
flags : fpu vme de pse tsc msr mce cx8 apic sep mtrr pge mca cmov pat clflush
dts acpi mmx fxsr sse sse2 tm pbe est tm2
bogomips : 200.13
clflush size : 64
Just for reference, the /proc/cpuinfo entry for 600 MHz CPU speed looks like this:
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 9
model name : Intel(R) Pentium(R) M processor 1600MHz
stepping : 5
cpu MHz : 600.000
cache size : 1024 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 2
wp : yes
flags : fpu vme de pse tsc msr mce cx8 apic sep mtrr pge mca cmov pat clflush
dts acpi mmx fxsr sse sse2 tm pbe est tm2
bogomips : 1200.80
clflush size : 64
This is the time to start watching log files, specifically /var/log/syslog. During my own tests with such low speeds, some warnings made it to the logfiles, but the majority of tests were cut short by a hard reboot. The machine would just reboot while being stress-tested for about an hour. To give you an idea about what to expect, let's have a look at my testing procedures.
At first, I started with the lowest possible voltage, 700 mV for 100 MHz, and not being successful in sustaining a stable system I increased the voltage according to the Electrical Specifications. My tests at 100 MHz with 700 mV, and 716 mV were both unsuccessfull, so now the entry for 100 MHz in speedstep-centrino.c looks like:
OP( 100, 732), /* 716 reboots under heavy load under X
700 kernel panic while idle */
Just look at the logfiles for what happens when setting 100 MHz with 700 mV voltage, and 716 mV respectively:
kernel: Unable to handle kernel paging request at virtual address 0009fb44 kernel: printing eip: kernel: c029c4eb kernel: *pde = 00000000 kernel: Oops: 0000 [#2] kernel: PREEMPT kernel: Modules linked in: loop kernel: CPU: 0 kernel: EIP: 0060:[] Not tainted kernel: EFLAGS: 00010096 (2.6.7) kernel: EIP is at acpi_processor_idle+0x7e/0x1c2 kernel: eax: 00000000 ebx: c0620000 ecx: 00000000 edx: 00000000 kernel: esi: 0009fb00 edi: c0662320 ebp: df719200 esp: c0620fc0 kernel: ds: 007b es: 007b ss: 0068 kernel: Process swapper (pid: 0, threadinfo=c0620000 task=c0550a40) kernel: Stack: 006bf007 00000001 c0620000 0009fb00 c0662320 006bf007 c01040e4 00000816 kernel: c062166a c0550a40 00000000 c06554f0 00000062 c0621380 c0662340 c010019f kernel: Call Trace: kernel: [ ] cpu_idle+0x34/0x40 kernel: [ ] start_kernel+0x18a/0x1d0 kernel: [ ] unknown_bootoption+0x0/0x120 kernel: kernel: Code: 8b 46 44 85 45 1c 74 09 fb 8b 56 34 e9 1e 01 00 00 ff 46 14 kernel: <0>Kernel panic: Attempted to kill the idle task! kernel: In idle task - not syncing and kdm: :0[2575]: Abnormal termination of greeter for display :0, code 125, signal 0 kernel: <6>MCE: The hardware reports a non fatal, correctable incident occurred on CPU 0. and kernel: Kernel panic: CPU context corrupt kernel: <6>MCE: The hardware reports a non fatal, correctable incident occurred on CPU 0.
It's that plain simple: If you notice similar entries in the logs, use the next higher voltage and repeat the stress-test. The same applies if your system reboots while being stress-tested (who would have guessed THAT, eh :-)
Just apply the procedure to the remaining frequencies you want to test; be sure to really stress the system. It's important to sustain a stable system! Falling prey to instabilities at the most unpleasant moment is certainly not amusing...
Concerning stress-testing... Number crunching, lots of number crunching is quite good for that purpose. Crypto stuff seems just to be made for this purpose ;-), so using any CPU-intensive utility out there would do. As a matter of fact, I use nasty in 50-200 instances, depending on the CPU frequency, whilst doing some copying of large data-chunks on an encrypted block-device using loop-aes, surfing on a remote machine via ssh, during which lots of scrolling (mouse wheel!) is done.
Typically system load exceeds 150, and gkrellm reports mostly 100% CPU activity, the number of running processes varies between 50 to 150+. Adapt the stress-test as needed, there's none suited for each and everyone. However, I observed that unstable voltages revealed themselves only on a system with both heavy load and high X activity, often during the first few minutes of the stress-test.
[top]
The following files are available for download:
[top]
[top]
[top]
Copyright © 2005 - 2010 markus reichelt.
If you want to contact me, send an email in plain text only to the address listed below; encrypted email is preferred. Have a look at my GnuPG Key Signing Policy.
Encrypted and anonymous message box available at https://privacybox.de/mareichelt.msg, or as Tor Hidden Service in case you prefer such a method of contact. Be advised that the subject will not be encrypted, only the text message itself. Also, in case you want a reply, please provide secure means of contact.
[top]
[ return to publications page ]
| markus reichelt <markus.reichelt@gmx.net>Last modified: 2008-04-19 | angstklausel - site policy - imprint | - Gegen Stasi 2.0 | - FSFE | - valid html | - valid CSS | - any browser |