Underclocking and undervolting a Banias CPU

markus reichelt, July 2005

v1.1.1, last modified: 2008-04-19, status: actively maintained

stylesheet: [green] [black]

Content

  1. Abstract
  2. What you need
  3. Modify the kernel source
  4. Relevant kernel config
  5. Tests concerning system stability
  6. Available Files
  7. Useful links
  8. Changelog
  9. License & Contact

Abstract

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]

What you need

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]

Modify the kernel source

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]

Relevant kernel config

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]

Tests concerning system stability

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]

Available Files

The following files are available for download:

[top]

Useful links

[top]

Changelog

Version 1.1.1, 2008-04-19:
Adapted to kernel 2.6.25, made patches available
Version 1.1.0, 2007-03-03:
Adapted to kernel 2.6.21-rc1.
Version 1.0.1, 2006-05-01:
Link to Key Signing Policy updated.
Version 1.0.0, 2005-07-09:
Initial Release.

[top]

License & Contact

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