Jump to content
AsereBLN

SpeedStep with AppleIntelCPUPowermanagement

Recommended Posts

First some background info:

Some general information about Intel SpeedStep can be found at Wikipedia. It's a technology adjust dynamically the processor frequency and voltage to reduce the overall power consumption.

The internal CPU frequency is determined by the frequency of the Front Side Bus (FSB) and the FSB-Multiplier. My Q9550 processor has a default FSB frequency of 333MHz and maximum FSB-Multiplier of 8.5, which gives 333Mhz * 8.5 = 2830 Mhz as internal CPU frequency. The lowest possible FSB-Multiplier is 6, which gives 333Mhz * 6 = 1998Mhz. The Q9550 allows the following FSB-Multipliers: 6, 6.5, 7, 7.5, 8 and 8.5.

SpeedStep dynamically changes these FSB-Multipliers and the cpu core voltage. At lower frequencies the cpu core voltage can be reduced to save even more energy. The Q9550 runs at 1998Mhz with 1.052V and at 2830MHz with 1.292V.

Please read also this Wikipedia article about ACPI, System States, Processor States, Performance States.

And the most important doc at all is the ACPI Spec.

P-States:

System is in S0. Processor is in C0. Depending on the load OSPM adjusts the FSB-Multiplier and the CPU Core Voltage. P-States are defined in the _PSS object. The _PCT object defines how the P-States are configrued.

C-States:

System is still in S0. Processor is in C0 (running) or C1... Cn (halted). The C-State C1 (HALT) is supported by all X86 CPU's and is entered by executing the "halt" instruction. C1E (Extended HALT) is entered then all cores of the CPU are in C1. In C1E the CPU frequency and voltage is reduced. You can see it as combination of C-States and P-States. C2 (STOP) and so on are deeper Halt States of the CPU, which more stopped/halted onchip units to reduce power consumption. These deeper C-States are entered by a (byte) read from a SystemIO address. C-States are defined in the in the FADT (P_BLK method, does not work under OS X) or in the _CST object.

The Q6600 has only C1E support, the Q9550 supports C1E...C4E.

BIOS Settings:

Please enable EIST (Enhanced Intel SpeedStep), C1E and if you have C2(E), C3(E) and so on.

LPC Driver:

LPC stands for Low Pin Count and this device is part of the southbridge. For some reason this driver must be loaded to have fully working SpeedStep with AppleIntelCPUPowermanagement. LPD device address in the DSDT is 0x1f0000. The device name in all Gigabyte DSDT is PX40. Here is a code snippet:

Device ([COLOR=Green]PX40[/COLOR])
{
Name (_ADR, [COLOR=Green]0x001F0000[/COLOR])
OperationRegion (PREV, PCI_Config, 0x08, One)
Scope (\)
{
Field (\_SB.PCI0.[COLOR=Green]PX40[/COLOR].PREV, ByteAcc, NoLock, Preserve)
{
REV0, 8
}
}
...

You can check whether the AppleLPC driver is loaded or not with SystemProfiler (Software->Extensions) or with this Terminal command:

 > kextstat | grep LPC
70 0 0x5c36b000 0x3000 0x2000 [COLOR=Green]com.apple.driver.AppleLPC[/COLOR] (1.4.9) <14 5 4 3>

The PCI Dev-Id of the LPC device is 0x3a18 for the ICH10 southbridge and 0x3a16 for the ICH10R. The driver is AppleLPC.kext. You can find them in /System/Library/Extensions. The problem is that AppleLPC does not load if you have an ICH10R southbridge, because it has no entry for the ICH10R Dev-Id in IONameMatch (see Info.plist in AppleLPC.kext). This can be fixed by patching the AppleLPC.kext itself or by patching the DSDT like this:

Device (PX40)
{
Name (_ADR, 0x001F0000)
[COLOR=Green]Method (_DSM, 4, NotSerialized)
{
Store (Package (0x02)
{
"device-id",
Buffer (0x04)
{
0x18, 0x3A, 0x00, 0x00
}
}, Local0)
DTGP (Arg0, Arg1, Arg2, Arg3, RefOf (Local0))
Return (Local0)
}[/COLOR]
OperationRegion (PREV, PCI_Config, 0x08, One)
Scope (\)
{
Field (\_SB.PCI0.PX40.PREV, ByteAcc, NoLock, Preserve)
{
REV0, 8
}
}
...

This fakes the Dev-Id to be an ICH10 one (0x3a18). It's also a good idea to rename the PX40 device into LPCB like on a real Mac. Please replace all PX40 you can find in the DSDT with LPCB.

Share this post


Link to post
Share on other sites

SSDT:

SSDT stands for Secondary System Description Table. It's an extension of the DSDT. There can be multiple SSDTs present. The DSDT and all SSDTs are joined to one name space. The Processor performance control (P-States, C-States) is typically defined using SSDTs. An Example: the root SSDT of my system GA-EP45-DS3 + Q9550 looks like this:

DefinitionBlock ("ssdt_cpupm.aml", "SSDT", 1, "PmRef", "CpuPm", 0x00003000)
{
External (\_PR_.CPU3, DeviceObj)
External (\_PR_.CPU2, DeviceObj)
External (\_PR_.CPU1, DeviceObj)
External (\_PR_.CPU0, DeviceObj)

Scope (\)
{
Name ([COLOR=Green]SSDT[/COLOR], Package (0x18)
{
"[COLOR=Green]CPU0IST[/COLOR] ",
[COLOR=Green]0xCFEEE7D0[/COLOR],
[COLOR=Green]0x0000022A[/COLOR],
"CPU1IST ",
0xCFEEEC90,
0x00000152,
"[COLOR=blue]CPU0CST[/COLOR] ",
[COLOR=blue]0xCFEEF0B0[/COLOR],
[COLOR=blue]0x0000018A[/COLOR],
"CPU1CST ",
0xCFEEF240,
0x0000018A,
"CPU2IST ",
0xCFEEEDF0,
0x00000152,
"CPU3IST ",
0xCFEEEF50,
0x00000152,
"CPU2CST ",
0xCFEEF3D0,
0x0000018A,
"CPU3CST ",
0xCFEEF560,
0x0000018A
})
Name (CFGD, 0x040383F2)
Name (\PDC0, 0x80000000)
Name (\PDC1, 0x80000000)
Name (\PDC2, 0x80000000)
Name (\PDC3, 0x80000000)
}

Scope (\_PR.CPU0)
{
Name (HI0, 0x00)
Name (HC0, 0x00)
Name (TLD0, 0x00)
Method ([COLOR=Red]_PDC[/COLOR], 1, NotSerialized)
{
CreateDWordField (Arg0, 0x08, CAP0)
[COLOR=red]Store (CAP0, PDC0)[/COLOR]
If (LEqual (TLD0, 0x00))
{
[COLOR=red]If (LEqual (And (PDC0, 0x0A), 0x0A))[/COLOR]
{
If (And (CFGD, 0x02))
{
OperationRegion (IST0, SystemMemory, DerefOf (Index (SSDT, 0x01)), DerefOf (Index (SSDT, 0x02)))
Load (IST0, HI0)
}
Store (0x01, TLD0)
}
}
}
}

Scope (\_PR.CPU1)
{
Name (HI1, 0x00)
Name (HC1, 0x00)
Name (TLD1, 0x00)
Method (_PDC, 1, NotSerialized)
{
CreateDWordField (Arg0, 0x08, CAP1)
Store (CAP1, PDC1)
If (LEqual (TLD1, 0x00))
{
If (LEqual (And (PDC1, 0x0A), 0x0A))
{
If (And (CFGD, 0x02))
{
OperationRegion (IST1, SystemMemory, DerefOf (Index (SSDT, 0x04)), DerefOf (Index (SSDT, 0x05)))
Load (IST1, HI1)
}
If (And (CFGD, 0x10))
{
OperationRegion (CST1, SystemMemory, DerefOf (Index (SSDT, 0x0A)), DerefOf (Index (SSDT, 0x0B)))
Load (CST1, HC1)
}
Store (0x01, TLD1)
}
}
}
}

Scope (\_PR.CPU2)
{
Name (HI2, 0x00)
Name (HC2, 0x00)
Name (TLD2, 0x00)
Method (_PDC, 1, NotSerialized)
{
CreateDWordField (Arg0, 0x08, CAP2)
Store (CAP2, PDC2)
If (LEqual (TLD2, 0x00))
{
If (LEqual (And (PDC2, 0x0A), 0x0A))
{
If (And (CFGD, 0x02))
{
OperationRegion (IST2, SystemMemory, DerefOf (Index (SSDT, 0x0D)), DerefOf (Index (SSDT, 0x0E)))
Load (IST2, HI2)
}
If (And (CFGD, 0x10))
{
OperationRegion (CST2, SystemMemory, DerefOf (Index (SSDT, 0x13)), DerefOf (Index (SSDT, 0x14)))
Load (CST2, HC2)
}
Store (0x01, TLD2)
}
}
}
}

Scope (\_PR.CPU3)
{
Name (HI3, 0x00)
Name (HC3, 0x00)
Name (TLD3, 0x00)
Method (_PDC, 1, NotSerialized)
{
CreateDWordField (Arg0, 0x08, CAP3)
Store (CAP3, PDC3)
If (LEqual (TLD3, 0x00))
{
If (LEqual (And (PDC3, 0x0A), 0x0A))
{
If (And (CFGD, 0x02))
{
OperationRegion (IST3, SystemMemory, DerefOf (Index (SSDT, 0x10)), DerefOf (Index (SSDT, 0x11)))
Load (IST3, HI3)
}
If (And (CFGD, 0x10))
{
OperationRegion (CST3, SystemMemory, DerefOf (Index (SSDT, 0x16)), DerefOf (Index (SSDT, 0x17)))
Load (CST3, HC3)
}
Store (0x01, TLD3)
}
}
}
}
}

The SSDT Package (marked green) defines additional SSDTs which are loaded at runtime with the Load() command. P-States by the "CPUxIST" (green) and C-States by the CPUxCST (blue) address/length pairs. To understand the code it's important to understand the _PDC method (red). _PDC stands for Processor Driver Capabilities. It is used by OSPM to tell the supported powermanagement capabilities. They are stored in the DWORD PDCx (red). The actual values are defined in Table 1 of the Intel Processor Vendor Specific ACPI document.

All further SSDTs are hardcoded in ROM. For instance the SSDT "CPU0IST" can be found at address 0xcfeee7d0 and has a length of 0x22a bytes. Here is a dump of it:

DefinitionBlock ("ssdt_cpu0ist.aml", "SSDT", 1, "PmRef", "Cpu0Ist", 0x00003000)
{
External (CFGD)
External (\_PR_.CPU0, DeviceObj)

Scope (\_PR.CPU0)
{
Method (_PPC, 0, NotSerialized)
{
Return (0x00)
}

Method (_PCT, 0, NotSerialized)
{
If (LEqual (And (CFGD, 0x00060000), 0x00020000))
{
Return (Package (0x02)
{
ResourceTemplate () { Register (SystemIO, 0x10, 0x00, 0x0000000000000880, ,) },
ResourceTemplate () { Register (SystemIO, 0x10, 0x00, 0x0000000000000882, ,) }
})
}
If (LEqual (And (CFGD, 0x00060000), 0x00040000))
{
Return (Package (0x02)
{
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000, ,) },
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000, ,) },
})
}
If (LOr (And (CFGD, 0x4000), And (CFGD, 0x00010000)))
{
Return (Package (0x02)
{
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000, ,) },
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000, ,) },
})
}
Return (Package (0x02)
{
ResourceTemplate () { Register (SystemIO, 0x10, 0x00, 0x0000000000000880, ,) },
ResourceTemplate () { Register (SystemIO, 0x10, 0x00, 0x0000000000000882, ,) }
})
}

Method (_PSS, 0, NotSerialized)
{
If (LEqual (And (CFGD, 0x00060000), 0x00020000))
{
Return (SPSS)
}
If (LEqual (And (CFGD, 0x00060000), 0x00040000))
{
Return (NPSS)
}
If (LOr (And (CFGD, 0x4000), And (CFGD, 0x00010000)))
{
Return (NPSS)
}
Return (SPSS)
}

Name (SPSS, Package (0x02)
{
Package (0x06) { 0x00000B12, 0x000157C0, 0x000000A0, 0x0000000A, 0x00000036, 0x00000000 },
Package (0x06) { 0x000007D0, 0x0000DAC0, 0x000000A0, 0x0000000A, 0x00000136, 0x00000001 }
})
Name (NPSS, Package (0x02)
{
Package (0x06) { 0x00000B12, 0x000157C0, 0x0000000A, 0x0000000A, 0x00004825, 0x00004825 },
Package (0x06) { 0x000007D0, 0x0000DAC0, 0x0000000A, 0x0000000A, 0x00000616, 0x00000616 }
})
}
}

The actual P-States are defined in the SPSS (used with SystemIO) and in the NPSS (FFixedHW) package. This example has two P-States, each one with 6 values. These values are: Core Frequency in MHz, Power consumption in mW, Latency in ms, Bus Master Latency in ms, PERF_CTRL word, Status. FSB-Multiplier and CPU core voltage are defined in PERF_CTRL. More info at chapter 8.4.4.2 in the ACPI spec.

Did you've noticed the CFGD value? It's something like the ABLN value in my patched DSDTs, a static configuration DWORD based on BIOS settings. On my system it's defined in the root SSDT:

Name (CFGD, 0x040383F2)

Because it's a static value and does not change at runtime you can resolve many of the CFGD terms. The functions LEqual, LOr, And... are explained in the ACPI Spec. An example:

If (LEqual (And (CFGD, 0x00060000), 0x00020000))
If (LEqual (And (0x040383F2, 0x00060000), 0x00020000))
If (LEqual (0x00020000, 0x00020000))
= TRUE

or another one:

If (LOr (And (CFGD, 0x4000), And (CFGD, 0x00010000)))
If (LOr (And (0x040383F2, 0x00004000), And (0x040383F2, 0x00010000)))
If (LOr (0x00000000), And (0x040383F2, 0x00010000)))
If (LOr (0x00000000, 0x00010000))
=TRUE

Share this post


Link to post
Share on other sites

Dumping SSDTs:

Please keep always in mind, that the SSDT depends on the CPU you are using. If you change your CPU, or if you change something CPU related in the BIOS, then the SSDT might might be change. For instance: if you change the FSB multiplier, then the _PSS object will be different. To be completely sure, whether a particular BIOS setting changes your DSDT/SSDT just dump all tables before and after changing the BIOS setting and compare both version.

To dump the SSDTs use Linux. I will use an Ubuntu 9.10 64Bit LiveCD for this guide. You can download it here.

Boot from the LiveCD. Install acpidump. I don't know why, but under 9.10 I cannot install it using "apt-get install acpidump". But no problem. Just open this guide from Linux and make click here if you run the 32Bit version and here if you run the 64Bit version of Ubuntu.

While booting the Linux Kernel (normally, maybe your Linux do not) dumps some info of all found ACPI tables, like name, address and length. We will use this info to get the SSDTs. Start a Terminal (Application -> Accessoirs -> Terminal) and enter these command:

ubuntu@ubuntu:~$ sudo -s
root@ubuntu:~# dmesg -s65536 > dmesg.log
root@ubuntu:~# cat dmesg.log | grep -i ssdt
[ 0.000000] ACPI: SSDT 00000000[COLOR=Green]cfeef0b0[/COLOR] 00[COLOR=Blue]18A[/COLOR] (v01 PmRef [COLOR=Red]Cpu0Cst[/COLOR] 00003001 INTL 20040311)
[ 0.000000] ACPI: SSDT 00000000[COLOR=Green]cfeef240[/COLOR] 00[COLOR=Blue]18A[/COLOR] (v01 PmRef [COLOR=Red]Cpu1Cst[/COLOR] 00003001 INTL 20040311)
[ 0.000000] ACPI: SSDT 00000000[COLOR=Green]cfeef3d0[/COLOR] 00[COLOR=Blue]18A[/COLOR] (v01 PmRef [COLOR=Red]Cpu2Cst[/COLOR] 00003001 INTL 20040311)
[ 0.000000] ACPI: SSDT 00000000[COLOR=Green]cfeef560[/COLOR] 00[COLOR=Blue]18A[/COLOR] (v01 PmRef [COLOR=Red]Cpu3Cst[/COLOR] 00003001 INTL 20040311)
[ 0.000000] ACPI: SSDT 00000000[COLOR=Green]cfeef6f0[/COLOR] 00[COLOR=Blue]3AB[/COLOR] (v01 PmRef [COLOR=Red]CpuPm[/COLOR] 00003000 INTL 20040311)
[ 1.706573] ACPI: SSDT 00000000[COLOR=Green]cfeee7d0[/COLOR] 00[COLOR=Blue]22A[/COLOR] (v01 PmRef [COLOR=Red]Cpu0Ist[/COLOR] 00003000 INTL 20040311)
[ 1.706924] ACPI: SSDT 00000000[COLOR=Green]cfeeec90[/COLOR] 00[COLOR=Blue]152[/COLOR] (v01 PmRef [COLOR=Red]Cpu1Ist[/COLOR] 00003000 INTL 20040311)
[ 1.707434] ACPI: SSDT 00000000[COLOR=Green]cfeeedf0[/COLOR] 00[COLOR=Blue]152[/COLOR] (v01 PmRef [COLOR=Red]Cpu2Ist[/COLOR] 00003000 INTL 20040311)
[ 1.708011] ACPI: SSDT 00000000[COLOR=Green]cfeeef50[/COLOR] 00[COLOR=Blue]152[/COLOR] (v01 PmRef [COLOR=Red]Cpu3Ist[/COLOR] 00003000 INTL 20040311)
root@ubuntu:~#

"dmesg" dumps the kernel message buffer. The output is piped into grep to filter out all lines which are not containing the string "SSDT". As you can see I get 9 SSDTs on my system. This might be completely different on your system. I've marked the table address green, the table lenght blue and the table name red. The SSDT root table has the name CpuPm. The CpuXIst tables are for P-States and the CpuXCst for the C-States.

Now dump all these SSDTs using acpidump:


root@ubuntu:~# acpidump -a 0xcfeef0b0 -l 0x18a > ssdt_cpu0cst.aml
root@ubuntu:~# acpidump -a 0xcfeef240 -l 0x18a > ssdt_cpu1cst.aml
root@ubuntu:~# acpidump -a 0xcfeef3d0 -l 0x18a > ssdt_cpu2cst.aml
root@ubuntu:~# acpidump -a 0xcfeef560 -l 0x18a > ssdt_cpu3cst.aml
root@ubuntu:~# acpidump -a 0xcfeef6f0 -l 0x3ab > ssdt_cpupm.aml
root@ubuntu:~# acpidump -a 0xcfeee7d0 -l 0x22a > ssdt_cpu0ist.aml
root@ubuntu:~# acpidump -a 0xcfeeec90 -l 0x152 > ssdt_cpu1ist.aml
root@ubuntu:~# acpidump -a 0xcfeeedf0 -l 0x152 > ssdt_cpu2ist.aml
root@ubuntu:~# acpidump -a 0xcfeeef50 -l 0x152 > ssdt_cpu3ist.aml
root@ubuntu:~# chown ubuntu:ubuntu *.aml

The "chown" command at the end changes the ownership of the aml files, so that you can copy them by drag-n-drop. Copy all your SSDT aml files onto a USB-Stick or something similar.

Share this post


Link to post
Share on other sites

SSDT and BIOS Settings:

Powermanagementoptions (EIST/P-States, C-States, Thermal throtteling) can be configured in the BIOS under "Advanced BIOS Features". I have a GA-EP45-DS3 (Bios F10a), a Q9550 (Stepping E0) and have this configurations options:

  • CPU Enhanced Halt (C1E)
  • C2/C2E State Support
  • C4/C4E State Support
  • CPU Thermal Monitor 2 (TM2)
  • CPU EIST Function

With my "old" Q6600 CPU I got this options:

  • CPU Enhanced Halt (C1E)
  • CPU Thermal Monitor 2 (TM2)
  • CPU EIST Function

The Q6600 supports only the C1E C-State, hence the BIOS does not offer the C2/C2E and C4/C4E options. It depends on the CPU what options you will see. Enable at least EIST and C1E. EIST for the P-States and C1E for C-States, although C1E only will give you no _CST on Gigabyte mainboards. But this is no problem, because every x86 CPU supports the HALT instruction, which is be used to enter C-State C1/C1E.

What does these options mean regarding the SSDTs? I've made a test, trying out all possible combinations. EIST will give you SSDT support for P-States. SSDT support for C-States (_CST objects) is available if EIST is enabled and at least C2/C2E. If you disable EIST, then the BIOS does not supply any SSDT at all. For me a bug, because P-States (EIST or SpeedStepping) and C-States are two different things. It's possible to support C-States (C1/C2/C3/C4) and no P-States, or P-States and no C-States, or P-States and C-States.

EIST enables the CpuPM, Cpu0Ist, Cpu1Ist, Cpu2Ist and the Cpu3Ist SSDTs.

C2/C2E enables additionally the Cpu0Cst, Cpu1Cst, Cpu2Cst and the Cpu3Cst SSDTs. But only if EIST is enabled. C4/C4E results in a different CFGD value in the CpuPm SSDT, which in turn is used by the _CST method to select the correct C-State array to be returned. I get these values, depending on EIST, C1E, C2E and C4E:

  • Name (CFGD, 0x04038302) - EIST
  • Name (CFGD, 0x04038302) - EIST/C1E
  • Name (CFGD, 0x04038332) - EIST/C1E/C2E
  • Name (CFGD, 0x040383F2) - EIST/C1E/C2E/C4E

To understand, what this CFGD values does, have first a look at the CpuPM "Root" SSDT:

DefinitionBlock ("ssdt_CpuPm.aml", "SSDT", 1, "PmRef", "CpuPm", 0x00003000)
{
External (\_PR_.CPU3, DeviceObj)
External (\_PR_.CPU2, DeviceObj)
External (\_PR_.CPU1, DeviceObj)
External (\_PR_.CPU0, DeviceObj)
Scope (\)
{
Name (SSDT, Package (0x18)
{
"CPU0IST ", 0xCFEEE7D0, 0x0000022A,
"CPU1IST ", 0xCFEEEC90, 0x00000152,
"CPU0CST ", 0xCFEEF0B0, 0x0000018A,
"CPU1CST ", 0xCFEEF240, 0x0000018A,
"CPU2IST ", 0xCFEEEDF0, 0x00000152,
"CPU3IST ", 0xCFEEEF50, 0x00000152,
"CPU2CST ", 0xCFEEF3D0, 0x0000018A,
"CPU3CST ", 0xCFEEF560, 0x0000018A
})
[COLOR="Blue"]Name (CFGD, 0x040383F2)[/COLOR]
Name (\PDC0, 0x80000000)
Name (\PDC1, 0x80000000)
Name (\PDC2, 0x80000000)
Name (\PDC3, 0x80000000)
}
Scope (\_PR.CPU0)
{
Name (HI0, 0x00)
Name (HC0, 0x00)
Name (TLD0, 0x00)
Method (_PDC, 1, NotSerialized)
{
CreateDWordField (Arg0, 0x08, CAP0)
Store (CAP0, PDC0)
If (LEqual (TLD0, 0x00))
{
If (LEqual (And (PDC0, 0x0A), 0x0A))
{
[COLOR="green"]If (And (CFGD, 0x02))[/COLOR]
{
OperationRegion (IST0, SystemMemory, DerefOf (Index (SSDT, 0x01)), DerefOf (Index (SSDT, 0x02)))
Load (IST0, HI0)
}
Store (0x01, TLD0)
}
}
}
}
Scope (\_PR.CPU1)
{
Name (HI1, 0x00)
Name (HC1, 0x00)
Name (TLD1, 0x00)
Method (_PDC, 1, NotSerialized)
{
CreateDWordField (Arg0, 0x08, CAP1)
Store (CAP1, PDC1)
If (LEqual (TLD1, 0x00))
{
If (LEqual (And (PDC1, 0x0A), 0x0A))
{
[COLOR="Green"]If (And (CFGD, 0x02))[/COLOR]
{
OperationRegion (IST1, SystemMemory, DerefOf (Index (SSDT, 0x04)), DerefOf (Index (SSDT, 0x05)))
Load (IST1, HI1)
}
[COLOR="Red"]If (And (CFGD, 0x10))[/COLOR]
{
OperationRegion (CST1, SystemMemory, DerefOf (Index (SSDT, 0x0A)), DerefOf (Index (SSDT, 0x0B)))
Load (CST1, HC1)
}
Store (0x01, TLD1)
}
}
}
}
[B]...[/B]
}

The definition of the CFGD is marked blue. The evaluation of CFGD for P-States (Ist) is marked green and the evaluation of CFGD for the C-States (Cst) is marked red.

How does the If () resolve for the different CFDG values:

And (0x04038302, 0x02) = TRUE

And (0x04038302, 0x10) = FALSE

And (0x04038332, 0x10) = TRUE

And (0x040383F2, 0x10) = TRUE

The CpuXIst SSDT will be always loaded, the Cpu0Cst only if you have enabled at least C2/C2E. Another strange thing with the Gigabyte SSDT is, that the Cpu0Cst SSDT will not be loaded for CPU0. The Code is missing! Hence there will be no _CST method for the CPU0. A bug?

Share this post


Link to post
Share on other sites

Now have a look at the _CST method itself:

DefinitionBlock ("ssdt_Cpu0Cst.aml", "SSDT", 1, "PmRef", "Cpu0Cst", 0x00003001)
{
External (CFGD)
External (\_PR_.CPU0, DeviceObj)
Scope (\_PR.CPU0)
{
Method (_CST, 0, NotSerialized)
{
[COLOR="Blue"]If (And (CFGD, 0x80))
{
Return (Package (0x04)
{
0x03,
Package (0x04)
{
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000,,) },
0x01,
0x01,
0x03E8
},
Package (0x04)
{
ResourceTemplate () { Register (SystemIO, 0x08, 0x00, 0x0000000000000414,,) },
0x02,
0x01,
0x01F4
},
Package (0x04)
{
ResourceTemplate () { Register (SystemIO, 0x08, 0x00, 0x0000000000000416,,) },
0x03,
0x96,
0x64
}
})
}[/COLOR]
[COLOR="Green"]If (And (CFGD, 0x40))
{
Return (Package (0x04)
{
0x03,
Package (0x04)
{
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000,,) },
0x01,
0x01,
0x03E8
},
Package (0x04)
{
ResourceTemplate () { Register (SystemIO, 0x08, 0x00, 0x0000000000000414,,) },
0x02,
0x01,
0x01F4
},
Package (0x04)
{
ResourceTemplate () { Register (SystemIO, 0x08, 0x00, 0x0000000000000415,,) },
0x03,
0x55,
0xFA
}
})
}[/COLOR]
[COLOR="Red"]If (And (CFGD, 0x20))
{
Return (Package (0x03)
{
0x02,
Package (0x04)
{
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000,,) },
0x01,
0x01,
0x03E8
},
Package (0x04)
{
ResourceTemplate () { Register (SystemIO, 0x08, 0x00, 0x0000000000000414,,) },
0x02,
0x01,
0x01F4
}
})
}[/COLOR]
Return (Package (0x02)
{
0x01,
Package (0x04)
{
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000,,) },
0x01,
0x01,
0x03E8
}
})
}
}
}

The _CST object is defined in the ACPI spec chapter 8.4.2.1. Please read it to better understand how it's organized. _CST returns a variable-length Package that contains the following elements: Count (an Integer that contains the number of C-States) and a list of "Count" sub-packages. Each sub-package defines an address/register to be read to enter this CState, the C-State (1=C1, 2=C2, 3=C3... and so on), the latency to enter and leave this C-State and the average power consumption in this C-State.

The blue code block is executed if you have C1/C2/(C3)/C4 enabled. It configures the C-States C1/C2/C4 to be used by OSPM.

The green code block would be executed if you have C1/C2/(C3) enabled and C4 disabled. It configures the C-States C1/C2/C3 to be used by OSPM. This code branch is not used on my system (no C3 available).

The red code block is executed if you have C1/C2 enabled and (C3)/C4 disabled. It configures the C-States C1/C2 to be used by OSPM.

As default only C-State C1 is available, which is supported by all x86 CPU's.

Note: ACPI only defines the C-States C1, C2 and C3. If a platform supports more than 3 C-States. then you have to decide, which C-States should be used. For example the blue code block here uses C1, C2, C4 and leaves away the C3 C-State.

C1 is entered by executing the HALT instruction. The HALT instruction does not return until a "break event" occurs, for instance an interrupt. Because every x86 CPU supports this instruction, there must be nothing configured. It's always the HALT instruction. The other C-States like C2/C3/C4... need hardware support from outside the CPU. For instance, to force the CPU into C2-State the signal STPCLK# must be activated to the CPU. These powermanagement logic is located in the ICH10 southbridge. Read the Intel I/O Controller Hub 10 (ICH10) Family Datasheet chapter 13.8 for detailed information. Back to the C2 example: C2 is entered by reading a byte from the LV4 register (ICH10: chapter 13.8.3.6), which is mapped to IO-Space address P_BLK + 4. And P_BLK is defined in the DSDT here:

    Scope (_PR)
{
Processor (CPU0, 0x00, [COLOR="Green"]0x00000410[/COLOR], 0x06) {}
Processor (CPU1, 0x01, [COLOR="green"]0x00000410[/COLOR], 0x06) {}
Processor (CPU2, 0x02, [COLOR="green"]0x00000410[/COLOR], 0x06) {}
Processor (CPU3, 0x03, [COLOR="green"]0x00000410[/COLOR], 0x06) {}
}

0x410 + 4 = 0x414. It's IO-Space. Therefore you will see in the _CST object:

Package (0x04)
{
ResourceTemplate ()
{
Register ([COLOR="Green"]SystemIO[/COLOR],
[COLOR="Green"]0x08[/COLOR], // Bit Width
[COLOR="green"]0x00[/COLOR], // Bit Offset
[COLOR="green"]0x0000000000000414[/COLOR], // Address
,)
},
[COLOR="Red"]0x02[/COLOR],
0x01,
0x01F4
}

A SystemIO read of 8 bits at bit offset 0 and address 0x414 will lead to C-State C2. The byte read does not return until a "break event" occurs if C2/C2E is enabled. If it's disabled, then the read returns immediately doing nothing. C3 is entered by a read from P_BLK + 5 = 0x415 (ICH10: chapter 13.8.3.7). C4 is entered by a read from P_BLK + 6 = 0x416 (ICH10: chapter 13.8.3.8).

Share this post


Link to post
Share on other sites

Let's continue with P-States. The relevant objects in the SSDT for P-States are _PCT, _PSS and _PPC.

_PCT stands for Performance Control (ACPI spec chapter 8.4.4.1)and declares an interface that allows OSPM to transition to a specific performance state. I know to methods: one uses directly the CPU Performance Control Register (FFixedHW, 0x199) and the other one uses SystemIO to configure the P-State. I tried both methods on my system. Both are able to change the frequency, but only the direct method using the PERF_CTRL register could also change the voltage (checked with CPU-I).

_PSS stands for Performance Supported States(ACPI spec chapter 8.4.4.2). It declares the supported performance states to OSPM. It returns a package of all available P-States and each one declares Core Frequency, Power, Latency, Bus Master Latency, Control and Status.

_PPC stands for Performance Present Capabilities (ACPI spec chapter 8.4.4.3). It's is a method that dynamically indicates to OSPM the number of performance states currently supported. Returning 0 is fine and indicates that all P-States listed in _PSS are available.

My system looks like this:

DefinitionBlock ("ssdt_cpu0ist.aml", "SSDT", 1, "PmRef", "Cpu0Ist", 0x00003000)
{
External (CFGD)
External (\_PR_.CPU0, DeviceObj)

Scope (\_PR.CPU0)
{
Method ([COLOR=Red]_PPC[/COLOR], 0, NotSerialized)
{
Return (0x00)
}

Method ([COLOR=Blue]_PCT[/COLOR], 0, NotSerialized)
{
If (LEqual (And (CFGD, 0x00060000), 0x00020000))
{
Return (Package (0x02)
{
ResourceTemplate () { Register (SystemIO, 0x10, 0x00, 0x0000000000000880, ,) },
ResourceTemplate () { Register (SystemIO, 0x10, 0x00, 0x0000000000000882, ,) }
})
}
If (LEqual (And (CFGD, 0x00060000), 0x00040000))
{
Return (Package (0x02)
{
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000, ,) },
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000, ,) }
})
}
If (LOr (And (CFGD, 0x4000), And (CFGD, 0x00010000)))
{
Return (Package (0x02)
{
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000, ,) },
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000, ,) }
})
}
Return (Package (0x02)
{
ResourceTemplate () { Register (SystemIO, 0x10, 0x00, 0x0000000000000880, ,) },
ResourceTemplate () { Register (SystemIO, 0x10, 0x00, 0x0000000000000882, ,) }
})
}

Method ([COLOR=Green]_PSS[/COLOR], 0, NotSerialized)
{
If (LEqual (And (CFGD, 0x00060000), 0x00020000))
{
Return (SPSS)
}
If (LEqual (And (CFGD, 0x00060000), 0x00040000))
{
Return (NPSS)
}
If (LOr (And (CFGD, 0x4000), And (CFGD, 0x00010000)))
{
Return (NPSS)
}
Return (SPSS)
}

Name (SPSS, Package (0x02)
{
Package (0x06) { 0x00000B12, 0x000157C0, 0x000000A0, 0x0000000A, 0x00000036, 0x00000000 },
Package (0x06) { 0x000007D0, 0x0000DAC0, 0x000000A0, 0x0000000A, 0x00000136, 0x00000001 }
})
Name (NPSS, Package (0x02)
{
Package (0x06) { 0x00000B12, 0x000157C0, 0x0000000A, 0x0000000A, 0x00004825, 0x00004825 },
Package (0x06) { 0x000007D0, 0x0000DAC0, 0x0000000A, 0x0000000A, 0x00000616, 0x00000616 }
})
}
}

The CFGD is declared external here and it's defined in the "Root" SSDT:

Name (CFGD, 0x040383F2)

Until today I was not able to find a BIOS setting which changes CFGD in a way which has influence on the P-States. How they resolve:

LEqual (And (0x040383F2, 0x00060000), 0x00020000) = TRUE

LEqual (And (0x040383F2, 0x00060000), 0x00040000) = FALSE

LOr (And (0x040383F2, 0x00004000), And (0x040383F2, 0x00010000)) = TRUE

This means in my case that the P-States a handled using SystemIO, which in turn only switches the frequency and no the voltage. It coud be fixed by modifying CFGD to:

Name (CFGD, 0x040583F2)

Or just by removing all the SystemIO stuff which could look like this:

DefinitionBlock ("ssdt_cpu0ist.aml", "SSDT", 1, "PmRef", "Cpu0Ist", 0x00003000)
{
External (CFGD)
External (\_PR_.CPU0, DeviceObj)

Scope (\_PR.CPU0)
{
Method (_PPC, 0, NotSerialized)
{
Return (0x00)
}

Method (_PCT, 0, NotSerialized)
{
Return (Package (0x02)
{
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000, ,) },
ResourceTemplate () { Register (FFixedHW, 0x00, 0x00, 0x0000000000000000, ,) }
})
}

Method (_PSS, 0, NotSerialized)
{
Return (NPSS)
}

Name (NPSS, Package (0x02)
{
Package (0x06) { 0x00000B12, 0x000157C0, 0x0000000A, 0x0000000A, 0x00004825, 0x00004825 },
Package (0x06) { 0x000007D0, 0x0000DAC0, 0x0000000A, 0x0000000A, 0x00000616, 0x00000616 }
})
}
}

To be continued...

Please do not post until I'm finished!

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.