12.17. Using and Debugging FreeBSD ACPI

Written by Nate Lawson.
With contributions from Peter Schultz and Tom Rhodes.

ACPI is a fundamentally new way of discovering devices, managing power usage, and providing standardized access to various hardware previously managed by the BIOS. Progress is being made toward ACPI working on all systems, but bugs in some motherboards' ACPI Machine Language (AML) bytecode, incompleteness in FreeBSD's kernel subsystems, and bugs in the Intel® ACPI-CA interpreter continue to appear.

This section is intended to help users assist the FreeBSD ACPI maintainers in identifying the root cause of problems and in debugging and developing a solution.

12.17.1. Submitting Debugging Information


Before submitting a problem, ensure the latest BIOS version is installed and, if available, the embedded controller firmware version.

When submitting a problem, send the following information to freebsd-acpi@FreeBSD.org:

  • Description of the buggy behavior, including system type and model and anything that causes the bug to appear. Note as accurately as possible when the bug began occurring if it is new.

  • The output of dmesg(8) after running boot -v, including any error messages generated by the bug.

  • The dmesg(8) output from boot -v with ACPI disabled, if disabling it helps to fix the problem.

  • Output from sysctl hw.acpi. This lists which features the system offers.

  • The URL to a pasted version of the ACPI Source Language (ASL). Do not send the ASL directly to the list as it can be very large. Generate a copy of the ASL by running this command:

    # acpidump -dt > name-system.asl

    Substitute the login name for name and manufacturer/model for system. For example, use njl-FooCo6000.asl.

Most FreeBSD developers watch FreeBSD-CURRENT mailing list, but one should submit problems to freebsd-acpi to be sure it is seen. Be patient when waiting for a response. If the bug is not immediately apparent, submit a PR using send-pr(1). When entering a PR, include the same information as requested above. This helps developers to track the problem and resolve it. Do not send a PR without emailing freebsd-acpi first as it is likely that the problem has been reported before.

12.17.2. Background

ACPI is present in all modern computers that conform to the ia32 (x86), ia64 (Itanium), and amd64 (AMD) architectures. The full standard has many features including CPU performance management, power planes control, thermal zones, various battery systems, embedded controllers, and bus enumeration. Most systems implement less than the full standard. For instance, a desktop system usually only implements bus enumeration while a laptop might have cooling and battery management support as well. Laptops also have suspend and resume, with their own associated complexity.

An ACPI-compliant system has various components. The BIOS and chipset vendors provide various fixed tables, such as FADT, in memory that specify things like the APIC map (used for SMP), config registers, and simple configuration values. Additionally, a bytecode table, the Differentiated System Description Table DSDT, specifies a tree-like name space of devices and methods.

The ACPI driver must parse the fixed tables, implement an interpreter for the bytecode, and modify device drivers and the kernel to accept information from the ACPI subsystem. For FreeBSD, Intel® has provided an interpreter (ACPI-CA) that is shared with Linux® and NetBSD. The path to the ACPI-CA source code is src/sys/contrib/dev/acpica. The glue code that allows ACPI-CA to work on FreeBSD is in src/sys/dev/acpica/Osd. Finally, drivers that implement various ACPI devices are found in src/sys/dev/acpica.

12.17.3. Common Problems

For ACPI to work correctly, all the parts have to work correctly. Here are some common problems, in order of frequency of appearance, and some possible workarounds or fixes. Mouse Issues

In some cases, resuming from a suspend operation will cause the mouse to fail. A known work around is to add hint.psm.0.flags="0x3000" to /boot/loader.conf. If this does not work, consider sending a bug report using send-pr(1). Suspend/Resume

ACPI has three suspend to RAM (STR) states, S1-S3, and one suspend to disk state (STD), called S4. S5 is soft off and is the normal state the system is in when plugged in but not powered up. S4 can be implemented in two separate ways. S4BIOS is a BIOS-assisted suspend to disk. S4OS is implemented entirely by the operating system.

Start by checking sysctl hw.acpi for the suspend-related items. Here are the results for a Thinkpad:

hw.acpi.supported_sleep_state: S3 S4 S5 hw.acpi.s4bios: 0

Use acpiconf -s to test S3, S4OS, and S5. An s4bios of one (1), indicates S4BIOS support instead of S4 OS.

When testing suspend/resume, start with S1, if supported. This state is most likely to work since it does not require much driver support. No one has implemented S2, which is similar to S1. Next, try S3. This is the deepest STR state and requires a lot of driver support to properly reinitialize the hardware. If there are problems resuming, email freebsd-acpi. However, the problem may not be resolved quickly since due to the amount of drivers and hardware that need more testing and work.

A common problem with suspend/resume is that many device drivers do not save, restore, or reinitialize their firmware, registers, or device memory properly. As a first attempt at debugging the problem, try:

# sysctl debug.bootverbose=1 # sysctl debug.acpi.suspend_bounce=1 # acpiconf -s 3

This test emulates the suspend/resume cycle of all device drivers without actually going into S3 state. In some cases, problems such as losing firmware state, device watchdog time out, and retrying forever, can be captured with this method. Note that the system will not really enter S3 state, which means devices may not lose power, and many will work fine even if suspend/resume methods are totally missing, unlike real S3 state.

Harder cases require additional hardware, such as a serial port and cable for debugging through a serial console, a Firewire port and cable for using dcons(4), and kernel debugging skills.

To help isolate the problem, remove as many drivers from the kernel as possible. If it works, narrow down which driver is the problem by loading drivers until it fails again. Typically, binary drivers like nvidia.ko, display drivers, and USB will have the most problems while Ethernet interfaces usually work fine. If drivers can be properly loaded and unloaded, automate this by putting the appropriate commands in /etc/rc.suspend and /etc/rc.resume. Try setting hw.acpi.reset_video to 0 if the display is messed up after resume. Try setting longer or shorter values for hw.acpi.sleep_delay to see if that helps.

Try loading a recent Linux® distribution to see if suspend/resume works on the same hardware. If it works on Linux®, it is likely a FreeBSD driver problem. Narrowing down which driver causes the problem will assist developers in fixing the problem. Since the ACPI maintainers rarely maintain other drivers, such as sound or ATA, any driver problems should also be posted to the freebsd-current list and mailed to the driver maintainer. Advanced users can include debugging printf(3)s in a problematic driver to track down where in its resume function it hangs.

Finally, try disabling ACPI and enabling APM instead. If suspend/resume works with APM, stick with APM, especially on older hardware (pre-2000). It took vendors a while to get ACPI support correct and older hardware is more likely to have BIOS problems with ACPI. System Hangs

Most system hangs are a result of lost interrupts or an interrupt storm. Chipsets may have problems based on boot, how the BIOS configures interrupts before correctness of the APIC (MADT) table, and routing of the System Control Interrupt (SCI).

Interrupt storms can be distinguished from lost interrupts by checking the output of vmstat -i and looking at the line that has acpi0. If the counter is increasing at more than a couple per second, there is an interrupt storm. If the system appears hung, try breaking to DDB (CTRL+ALT+ESC on console) and type show interrupts.

When dealing with interrupt problems, try disabling APIC support with hint.apic.0.disabled="1" in /boot/loader.conf. Panics

Panics are relatively rare for ACPI and are the top priority to be fixed. The first step is to isolate the steps to reproduce the panic, if possible, and get a backtrace. Follow the advice for enabling options DDB and setting up a serial console in Section, “Entering the DDB Debugger from the Serial Line” or setting up a dump(8) partition. To get a backtrace in DDB, use tr. When handwriting the backtrace, get at least the last five and the top five lines in the trace.

Then, try to isolate the problem by booting with ACPI disabled. If that works, isolate the ACPI subsystem by using various values of debug.acpi.disable. See acpi(4) for some examples. System Powers Up After Suspend or Shutdown

First, try setting hw.acpi.disable_on_poweroff="0" in loader.conf(5). This keeps ACPI from disabling various events during the shutdown process. Some systems need this value set to 1 (the default) for the same reason. This usually fixes the problem of a system powering up spontaneously after a suspend or poweroff. Other Problems

For other problems with ACPI, such as it not working with a docking station or devices not being detected, email a description to freebsd-acpi. Some issues may be related to unfinished parts of the ACPI subsystem which might take a while to be implemented. Be patient and prepared to test patches.

12.17.4. ASL, acpidump(8), and IASL

Some BIOS vendors provide incorrect or buggy bytecode. This is usually manifested by kernel console messages like this:

ACPI-1287: *** Error: Method execution failed [\\_SB_.PCI0.LPC0.FIGD._STA] \\ (Node 0xc3f6d160), AE_NOT_FOUND

Often, these problems may be resolved by updating the BIOS to the latest revision. Most console messages are harmless, but if there are other problems like the battery status is not working, these messages are a good place to start looking for problems. The bytecode, known as AML, is compiled from a source language called ASL. The AML is found in the table known as the DSDT. To get a copy of the system's ASL, use acpidump(8). Include both -t, to show the contents of the fixed tables, and -d, to disassemble the AML. Refer to Section 12.17.1, “Submitting Debugging Information” for an example syntax.

The simplest first check is to recompile the ASL to check for errors. Warnings can usually be ignored, but errors are bugs that will usually prevent ACPI from working correctly. To recompile the ASL, issue the following command:

# iasl your.asl

12.17.5. Fixing the ASL

The goal of FreeBSD is for everyone to have working ACPI without any user intervention. At this point, workarounds are still being developed for common mistakes made by BIOS vendors. The Microsoft® interpreter (acpi.sys and acpiec.sys) does not strictly check for adherence to the standard, and thus many BIOS vendors who only test ACPI under Windows® never fix their ASL. FreeBSD developers continue to identify and document which non-standard behavior is allowed by Microsoft®'s interpreter and replicate it so that FreeBSD can work without forcing users to fix the ASL. As a workaround, and to help identify behavior, fix the ASL manually. If this works, send a diff(1) of the old and new ASL so developers can possibly work around the buggy behavior in ACPI-CA.

Here is a list of common error messages, their cause, and how to fix them: Operating System Dependencies

Some AML versions assume the user is running Windows®. To override this, set hw.acpi.osname="Windows 2001" in /boot/loader.conf, using the strings in the ASL. Missing Return Statements

Some methods do not explicitly return a value as the standard requires. While ACPI-CA does not handle this, FreeBSD has a workaround that allows it to return the value implicitly. Explicit return statements can be added where required if the value which should be returned is known. To force iasl(8) to compile the ASL, use the -f flag. Overriding the Default AML

After customizing your.asl, compile it with this command:

# iasl your.asl

Adding the -f flag forces creation of the AML, even if there are errors during compilation. Some errors, such as missing return statements, are automatically worked around by the interpreter.

The default output filename for iasl(8) is DSDT.aml. Load this file instead of the BIOS's buggy copy, which is still present in flash memory, by editing /boot/loader.conf as follows:

acpi_dsdt_load="YES" acpi_dsdt_name="/boot/DSDT.aml"

Be sure to copy DSDT.aml to /boot.

12.17.6. Getting Debugging Output from ACPI

The ACPI driver has a flexible debugging facility. A set of subsystems and the level of verbosity can be specified. The subsystems to debug are specified as layers and are broken down into ACPI-CA components (ACPI_ALL_COMPONENTS) and ACPI hardware support (ACPI_ALL_DRIVERS). The verbosity of debugging output is specified as the level and ranges from ACPI_LV_ERROR (just report errors) to ACPI_LV_VERBOSE (everything). The level is a bitmask so multiple options can be set at once, separated by spaces. In practice, a serial console should be used to log the output so it is not lost as the console message buffer flushes. A full list of the individual layers and levels is found in acpi(4).

Debugging output is not enabled by default. To enable it, add options ACPI_DEBUG to the kernel configuration file if ACPI is compiled into the kernel. Add ACPI_DEBUG=1 to /etc/make.conf to enable it globally. If it is a module, recompile just the acpi.ko module as follows:

# cd /sys/modules/acpi/acpi && make clean && make ACPI_DEBUG=1

Install acpi.ko in /boot/kernel and add the desired level and layer to /boot/loader.conf. This example enables debug messages for all ACPI-CA components and all ACPI hardware drivers such as (CPU and LID. It only outputs error messages at the least verbose level.

debug.acpi.layer="ACPI_ALL_COMPONENTS ACPI_ALL_DRIVERS" debug.acpi.level="ACPI_LV_ERROR"

If the required information is triggered by a specific event, such as a suspend and then resume, leave out changes to /boot/loader.conf and instead use sysctl(8) to specify the layer and level after booting and preparing the system for the specific event. The variables which can be set using sysctl(8) are named the same as the tunables in /boot/loader.conf.

12.17.7. References

More information about ACPI may be found in the following locations:

All FreeBSD documents are available for download at http://ftp.FreeBSD.org/pub/FreeBSD/doc/

Questions that are not answered by the documentation may be sent to <freebsd-questions@FreeBSD.org>.

Send questions about this document to <freebsd-doc@FreeBSD.org>.