ACPI In Depth
[[ This Article is imported from my previous blog. I’ll be removing it soon, so imported it here ]]
ACPI stands for Advanced Configuration & Power Interface. It is that nifty feature that automagically shuts down your PC when you press the power button, launches Amarok when you press a button on the laptop, monitors the battery and so on. This article aims to provide some information about ACPI in general and how it can be configured for better functionality. But first let’s understand what exactly ACPI does, its state in Linux and what are the common problems associated with it.
ACPI-What It does
A computer system is collection of several hardware parts, like a Processor, RAM, GPU, Buses et al. All these need power to run, which is supplied from the PCs SMPS. Now there are two approaches than can be used to supply power. First, we supply the power constantly even when the device is not in use, and secondly we switch off the device when it is not needed and switch is on when it is. Obviously, second approach makes more sense. A point to note here is that even though hardware components require very little power to work, there is always a danger of overheating. Some embedded systems have dedicated power management chips that do this task. ACPI does exactly that, plus a lot more. It detects the button press events and passes it on to the OS, it takes care of Timers, it sees how much power needs to be supplied to the CPU depending upon the load factor and so on. Traditionally all this fell into the hands of the BIOS, which led to widespread inconsistencies in the Power Management area. ACPI puts the complete power management into the hands of the Operating System. As a result you get a more intelligent interface to manage power and all things related. The only thing needed is an ACPI enabled Operating System, which leads to the next question.Problem with ACPI
So ACPI is a great specification, it lets you put your PC to sleep/suspend and save power and all. But then why does your linux box fail to recover from a suspend-resume cycle? The answer is again MS. ACPI standard was first implemented by Microsoft a long time ago, and due to the popularity of Windows hardware manufacturers chose to get their hardware passed by the Microsoft’s Hardware Compliance Tests. But herein lies the problem. Microsoft’s ACPI implementation differs slightly from the specification, and so came a lot of buggy BIOS’es that don’t fully follow the ACPI specs from Intel, which is what Linux implementation is based upon. So much for the history, now the question is, what does it affect on your system? For Linux developers, this provides a challenge as vendors are reluctant to change their BIOS to conform to Linux. Laptops are especially affected by buggy BIOS since they contain custom buttons and have to rely heavily on Power Management. The only solution here is to find out all the buggy hardware and provide custom fixes, which is the aim of this article.ACPI In Linux
ACPI in Linux is implemented pretty straightforwardly. The ACPI specification says that a ACPI enabled OS must be able to understand AML, the ACPI Machine Language. For the linux-kernel to understand the ACPI Machine Language it needs an interpreter inside the kernel, which amounts to about 72000 lines of code alone and is part of the kernel since the 2.6 series.AML is the pseudo code that the ACPI control methods and objects are written in.Therefore AML is the equivalent of Assembly Language on a PC. To write AML we need a high level language, like C is to Assembly, and that is called the ASL, the ACPI Source Language. Therefore an ASL program is compiled into AML, and since AML is understood by the linux kernel, it can generate an event based on the information. Each system can have a different specification, so each system has a different DSDT or the Differentiated System Description Table. The definition from the ACPI specs is this:
An OEM must supply a DSDT to an ACPI-compatible OS. The DSDT contains the Differentiated Definition Block, which supplies the implementation and configuration information about the base system. The OS always inserts the DSDT information into the ACPI Namespace at system boot time and never removes it.
So in the end it all boils down to the DSDT. If you have a buggy DSDT complying to the MS implementation, chances are it will not work properly in Linux. This DSDT contains all the information about your system the thermal zones, fans, battery states, sleep states and so on. This table is loaded from the BIOS and passed on to the ACPI layer, and it tells the kernel what to look out for and the dependencies among the hardware.ACPI - Hands On
Now, enough for the theory, lets get dirty with DSDT. Since DSDT is written in ASL, we need a compiler that can covert the ASL to AML, which can be understood by the kernel. So here is the missing link, the Intel’s ACPI-CA Compiler. The build instructions are mentioned at the bottom of the page. Let’s review what we have now. We have a DSDT somewhere in the BIOS which has been copied over to the linux kernel. We have a compiler that can compile the DSDT into ASL, which can be interpreted by the kernel’s interpretor. But before proceeding we need to find out if our DSDT is indeed buggy or not. To do this, run this:dmesg|grep ACPI
which will output like this:
BIOS-e820: 000000001f740000 - 000000001f750000 (ACPI data)
BIOS-e820: 000000001f750000 - 000000001f800000 (ACPI NVS)
ACPI: RSDP (v000 ACPIAM ) @ 0x000f7aa0
ACPI: RSDT (v001 INTEL D845GVS1 0x20040216 MSFT 0x00000097) @ 0x1f740000
ACPI: FADT (v001 INTEL D845GVS1 0x20040216 MSFT 0x00000097) @ 0x1f740200
ACPI: MADT (v001 INTEL D845GVS1 0x20040216 MSFT 0x00000097) @ 0x1f740300
ACPI: ASF! (v016 AMIASF I845GASF 0x00000001 MSFT 0x0100000d) @ 0x1f744330
ACPI: DSDT (v001 INTEL D845GVS1 0x0000010a MSFT 0x0100000d) @ 0x00000000
ACPI: Local APIC address 0xfee00000
ACPI: LAPIC (acpi_id[0x01] lapic_id[0x00] enabled)
ACPI: LAPIC (acpi_id[0x02] lapic_id[0x81] disabled)
ACPI: LAPIC_NMI (acpi_id[0x01] dfl dfl lint[0x1])
ACPI: LAPIC_NMI (acpi_id[0x02] dfl dfl lint[0x1])
ACPI: IOAPIC (id[0x01] address[0xfec00000] gsi_base[0])
ACPI: INT_SRC_OVR (bus 0 bus_irq 0 global_irq 2 dfl dfl)
ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 high level)
ACPI: IRQ0 used by override.
ACPI: IRQ2 used by override.
ACPI: IRQ9 used by override.
Using ACPI (MADT) for SMP configuration information
ACPI: Core revision 20060707
ACPI: bus type pci registered
ACPI: Interpreter enabled
ACPI: Using IOAPIC for interrupt routing
ACPI: PCI Root Bridge [PCI0] (0000:00)
PCI quirk: region 0400-047f claimed by ICH4 ACPI/GPIO/TCO
ACPI: PCI Interrupt Routing Table [\_SB_.PCI0._PRT]
ACPI: PCI Interrupt Routing Table [\_SB_.PCI0.P0P1._PRT]
ACPI: Power Resource [URP1] (off)
ACPI: Power Resource [FDDP] (off)
ACPI: Power Resource [LPTP] (off)
ACPI: PCI Interrupt Link [LNKA] (IRQs 3 4 5 6 7 9 10 *11 12 14 15)
ACPI: PCI Interrupt Link [LNKB] (IRQs *3 4 5 6 7 9 10 11 12 14 15)
ACPI: PCI Interrupt Link [LNKC] (IRQs 3 4 5 6 7 *9 10 11 12 14 15)
ACPI: PCI Interrupt Link [LNKD] (IRQs 3 4 *5 6 7 9 10 11 12 14 15)
ACPI: PCI Interrupt Link [LNKE] (IRQs 3 4 5 6 7 9 10 *11 12 14 15)
ACPI: PCI Interrupt Link [LNKF] (IRQs 3 4 5 6 7 9 10 11 12 14 15) *0, disabled.
ACPI: PCI Interrupt Link [LNKG] (IRQs 3 4 5 6 7 9 10 11 12 14 15) *0, disabled.
—————————snip——————————————————
In this bunch of gibberish, find out these lines, should be at the top:
ACPI: RSDT (v001 INTEL D845GVS1 0x20040216 MSFT 0x00000097) @ 0x1f740000
ACPI: FADT (v001 INTEL D845GVS1 0x20040216 MSFT 0x00000097) @ 0x1f740200
ACPI: MADT (v001 INTEL D845GVS1 0x20040216 MSFT 0x00000097) @ 0x1f740300
ACPI: ASF! (v016 AMIASF I845GASF 0x00000001 MSFT 0x0100000d) @ 0x1f744330
ACPI: DSDT (v001 INTEL D845GVS1 0x0000010a MSFT 0x0100000d) @ 0x00000000
The last line corresponds to the DSDT, and it says MSFT, so indeed my DSDT has been compiled with MS implementation. Though having this does not necessarily mean that there will be any problem, but it is just for info.
Now we want to find out if our DSDT differs from the linux implementation. To do this, we need to grab a copy of DSDT, and try to compile it with the Intel’s compiler, which is what Linux ACPI is based on. We do this next to grab a copy of the DSDT that the kernel has:
and then we need to compile it with Intel’s compiler we previously installed. To do that we first need to disassemble it.cat /proc/acpi/dsdt > dsdt.dat
which gives us two files dsdt.dsl, the disassembly file and dsdt.aml, the dsdt in AML.If you so wish, you can read the dsdt.dsl to see what a DSDT looks like. We now compile it with Intel’s compiler:iasl -d dsdt.dat
iasl -tc dsdt.dsl
At this point, you may get some errors and warning. This means that the DSDT the vendor has supplied does not adhere to the Intel’s specs. For example, I got the following output:
Intel ACPI Component Architecture
ASL Optimizing Compiler version 20061109 [Jul 13 2007]
Copyright (C) 2000 - 2006 Intel Corporation
Supports ACPI Specification Revision 3.0a
dsdt.dsl 1773: Acquire (MUT0, 0x0FFF)
Warning 1103 - Possible operator timeout is ignored ^
ASL Input: dsdt.dsl - 4429 lines, 146771 bytes, 1859 keywords
AML Output: dsdt.aml - 15712 bytes 581 named objects 1278 executable opcodes
Compilation complete. 0 Errors, 1 Warnings, 0 Remarks, 566 Optimizations
Here we see that the Intel compiler not only gives out errors and warnings, but it also provides optimizations to the DSDT. Therefore even though you do not have any errors or warnings, it is a good idea to check. BIOS is one area that is not very well known for good optimized code.
The steps needed to fix these errors/warnings and some common problems associated with ACPI will feature in Part 2 of this article. Comments, criticism, views, ideas, questions all are welcome, except spam.