Asus M6N-Kompendium: C1-C4 States Patch
Aus Wikibooks
Die C-States 1-4 ermögichen es der CPU, in tiefere Schlafzustände zu gelangen und so bis zu 200mA bzw. fast 3W Strom zu sparen. Das Dumme ist nun, daß der Kernel diese Zustände einleiten muß. Da das BIOS unseres M6N in dieser Hinsicht offenbar ziemlich "fucked up" ist, muß man nachhelfen und unter anderem die DSDT modifizieren sowie den Kernel etwas patchen. Das es auch anderst geht, zeigt Asus beim W3N, wo offenbar ohne weiteres die C-States 1-3 genutzt werden. EInschränkend muß außerdem gesagt werden, dass C3 und C4 bei aktiven Busmaster-Geräten (z.B eingesteckte USB-Maus) generell nicht benutzt werden.
Rahmenbedingung, bei dem diese Patches bekanntermaßen ohne Handarbeit angewendet werden können : M6N mit BIOS 214 und Kernel 2.6.11 sowie 2.6.12
Um das Patchen der DSDT kommt man nicht herum - wie die grundsätzlich funktioniert, steht im Kapitel DSDT. Jedoch wird keine der dort erwähnten Veränderungen durchgeführt, sondern anstatt dessen die dekompilierte DSDT-Datei mit diesem Diff gepatcht :
--- dsdt.dsl.orig 2005-05-15 17:39:17.000000000 +0200
+++ dsdt.dsl.gepatcht 2005-05-15 18:08:16.000000000 +0200
@@ -667,7 +667,8 @@
DMA (Compatibility, NotBusMaster, Transfer8) {}
IO (Decode16, 0x03BC, 0x03BC, 0x01, 0x04)
}
- //*** Missing EndDependentFunctions descriptor })
+ EndDependentFn ()
+ })
Name (EPPR, ResourceTemplate ()
{
IRQNoFlags () {3,4,5,6,7,10,11,12}
@@ -1565,15 +1566,15 @@
GPBE, 1
}
- OperationRegion (IO, SystemIO, DPRT, 0x05)
- Field (IO, ByteAcc, Lock, Preserve)
+ OperationRegion (IO_, SystemIO, DPRT, 0x05)
+ Field (IO_, ByteAcc, Lock, Preserve)
{
DAT0, 8,
Offset (0x04),
CMD0, 8
}
- Field (IO, ByteAcc, Lock, Preserve)
+ Field (IO_, ByteAcc, Lock, Preserve)
{
Offset (0x04),
OUTS, 1,
@@ -4459,7 +4460,7 @@
Scope (\_PR)
{
- Processor (CPU1, 0x01, 0x00000410, 0x07)
+ Processor (CPU1, 0x01, 0x00000410, 0x06)
{
Method (_CST, 0, NotSerialized)
{
@@ -4507,7 +4508,7 @@
},
0x02,
- 0x01,
+ 0x0A,
0x03E8
},
@@ -4519,7 +4520,7 @@
},
0x03,
- 0x01,
+ 0x14,
0x01F4
},
@@ -4530,8 +4531,8 @@
Register (SystemIO, 0x08, 0x00, 0x0000000000000416)
},
- 0x04,
- 0x02,
+ 0x03,
+ 0x1E,
0xFA
}
})
@@ -4562,19 +4563,18 @@
Add (\PMBS, 0x14, Local0)
Store (Local0, Index (DerefOf (Index (DerefOf (Index (NOC3, 0x01)), 0x00)), 0x07))
Store (ShiftRight (Local0, 0x08), Index (DerefOf (Index (DerefOf (Index (NOC3, 0x01)), 0x00)), 0x08))
- If (\_SB.INV7)
+ /*If (\_SB.INV7)
{
Return (NOC3)
- }
-
- If (\_SB.BATO)
- {
+ }*/
+ /*If (\_SB.BATO)
+ {*/
Return (BCST)
- }
+ /*}
Else
{
Return (ACST)
- }
+ }*/
}
Name (_PCT, Package (0x02)
@@ -5158,29 +5158,22 @@
}
}
- If (SS1)
- {
+
Name (\_SB.PCI0._S1D, 0x02)
Name (\_SB.PCI0.P0P1._S1D, 0x02)
Name (\_SB.PCI0.USB1._S1D, 0x02)
Name (\_SB.PCI0.USB2._S1D, 0x02)
Name (\_SB.PCI0.USB3._S1D, 0x02)
- }
- If (SS3)
- {
Name (\_SB.PCI0._S3D, 0x02)
Name (\_SB.PCI0.P0P1._S3D, 0x02)
Name (\_SB.PCI0.USB1._S3D, 0x02)
Name (\_SB.PCI0.USB2._S3D, 0x02)
Name (\_SB.PCI0.USB3._S3D, 0x02)
- }
- If (SS4)
- {
Name (\_SB.PCI0._S4D, 0x02)
Name (\_SB.PCI0.P0P1._S4D, 0x02)
- }
+
Name (IOXB, 0x05C0)
Name (IOXL, 0x10)
@@ -5697,8 +5690,6 @@
0x00,
0x00
})
- If (SS3)
- {
Name (_S3, Package (0x04)
{
0x05,
@@ -5706,10 +5697,7 @@
0x00,
0x00
})
- }
- If (SS4)
- {
Name (_S4, Package (0x04)
{
0x06,
@@ -5717,7 +5705,6 @@
0x00,
0x00
})
- }
Name (_S5, Package (0x04)
{
Die DSDT wird nun wie im Wiki-Abschnitt DSDT beschrieben mit dem IASL kompiliert. Ausserdem muß dieser C1-Patch auf den Kernel angewandt werden :
Für den Kernel 2.6.13 hat Scotch den Patch[3] aktualisiert und wir dürfen sogar hoffen das er bald in den Kernel aufgenommen wird. Die unten zu sehende Version passt für 2.6.11 und 2.6.12 :
--- ./drivers/acpi/processor_idle.c 2005-04-16 17:13:44.000000000 +0200
+++ ./drivers/acpi/processor_idle.c 2005-04-18 14:13:52.000000000 +0200
@@ -479,8 +479,6 @@
static int acpi_processor_get_power_info_fadt (struct acpi_processor *pr)
{
- int i;
-
ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_fadt");
if (!pr)
@@ -489,8 +487,7 @@
if (!pr->pblk)
return_VALUE(-ENODEV);
- for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++)
- memset(pr->power.states, 0, sizeof(struct acpi_processor_cx));
+ memset(pr->power.states, 0, ACPI_PROCESSOR_MAX_POWER * sizeof(struct acpi_processor_cx));
/* if info is obtained from pblk/fadt, type equals state */
pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
@@ -536,8 +533,8 @@
return_VALUE(-ENODEV);
pr->power.count = 0;
- for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++)
- memset(pr->power.states, 0, sizeof(struct acpi_processor_cx));
+
+ memset(pr->power.states, 0, ACPI_PROCESSOR_MAX_POWER * sizeof(struct acpi_processor_cx));
status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
if (ACPI_FAILURE(status)) {
@@ -609,6 +606,27 @@
cx.type = obj->integer.value;
+ //Test if the first entry is a C1 state, if not we fake one
+ if ((cx.type != ACPI_STATE_C1) && i == 1) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Faking C1 State"));
+ struct acpi_processor_cx c1_fake;
+ memset(&c1_fake, 0, sizeof(c1_fake));
+
+ c1_fake.address = 0;
+ c1_fake.type = ACPI_STATE_C1;
+ c1_fake.latency = 0; //How long needs a HLT instruction to execute ?
+ c1_fake.power = 0; //We don't know anything about the power consumption so we set it to 0
+ //We copy our fake C1 state over to the power states
+ (pr->power.count)++;
+ memcpy(&(pr->power.states[pr->power.count]), &c1_fake, sizeof(c1_fake));
+ //Finally we avoid to have more power states than ACPI_PROCESSOR_MAX_POWER
+ if(count == ACPI_PROCESSOR_MAX_POWER)
+ count--;
+
+ //c1_fake should be freed automaticaly
+ }
+
+
if ((cx.type != ACPI_STATE_C1) &&
(reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
continue;
Nun den neuen Kernel konfigurieren und bei der Konfiguration (z.B. mit xconfig) unter /Power Management/ACPI/Inculde Custom DSDT/Custom DSDT file/ die frisch kompilierte DSDT (z.B. /usr/src/dsdt.dsl.hex) zur integration in den Kernel angeben. Nun den Kernel neu übersetzen und installieren.
Ob diese Maßnahmen erfolgreich waren kann so kontrolliert werden :
user@host:~$ sudo watch -n1 cat /proc/acpi/processor/CPU1/power
Every 1,0s: cat /proc/acpi/processor/CPU1/power
active state: C2
max_cstate: C8
bus master activity: ffffffff
states:
C1: type[C1] promotion[C2] demotion[--] latency[000] usage[00112270]
*C2: type[C2] promotion[C3] demotion[C1] latency[010] usage[06256214]
C3: type[C3] promotion[C4] demotion[C2] latency[020] usage[00000420]
C4: type[C3] promotion[--] demotion[C3] latency[030] usage[00005184]
Man sieht also, daß alle C-States benutzt werden. Ist keine "bus master activity" vorhanden, wird auch C4 genutzt wodurch die CPU besonders Tief schläft und so mehr Strom spart. Analog dazu kann im Akku-Betrieb der aktuelle Verbrauch so beobachtet werden :
user@host:~$ sudo watch -n1 cat /proc/acpi/battery/BAT0/state
Ein weiteres Einsaprpotential ergibt sich aus der optimierung der Spannungstabellen des Kernel für die Banias und Dothan-Prozessoren und der Stromsparfunktion von X.Org für die Radeon-Chips [4]. Auf diese Weise ist es bei laufender Festplatte und geringer Display-Helligkeit möglich während der Arbeit mit einem Verbrauch von 10-12 Watt aus zu kommen.
← ACPI | Inhalt | Netzwerk + Internet →