Linux ACPI-HOWTO, The Sequel

Ariel Glenn

2005-10-19

Revision History
Revision 0.2eRevised by: atg
update [FIXME] list; custom DSDT in kernel and in initrd; initramfs notes; overview of ACPI tables; lvm corrections
Revision 0.2dRevised by: atg
2.6.14-rc4; Nvidia driver with swsusp2 notes; swsusp3 notes; ACPI4Linux wiki live again; swsusp* comparison
Revision 0.2cRevised by: atg
Nvidia console switching problem for swsusp1 noted; swsusp2 notes; 2.6.14-rc3; ^T and other typos
Revision 0.2bRevised by: atg
Software Suspend (swsusp1) notes added; Dave Jones in credits
Revision 0.2aRevised by: atg
Clean up markup and typos; update Jens Axboe SATA patch info; 2.6.14-rc2; video patch not needed
Revision 0.2Revised by: atg
Get a laptop 4 years later and rewrite the whole fscking thing for kernel 2.6.13
Revision 0.1eRevised by: atg
Fix typos; move full text of GPL to separate document; bug reports now go to Andy Grover
Revision 0.1dRevised by: atg
Added information about libpopt, required for build of acpictl (included in acpid)
Revision 0.1cRevised by: atg
describe pmtest util, /proc interface, reduced functionality of new acpid, changes to driver options

This document provides an overview of the ACPI subsystem in Linux, including kernel configuration, acpid support daemon, supporting user applications, and common problems.


Table of Contents
1. About this document
1.1. Introduction
1.2. Copyright and License
1.3. Disclaimer
1.4. Credits/Contributors
1.5. Feedback
1.6. [FIXME]s
2. Overview of ACPI
2.1. What is power management?
2.2. What is ACPI?
2.3. What is the difference between ACPI and APM?
2.4. What ACPI capabilities are supported under Linux?
3. Hardware requirements
3.1. What hardware is supported?
3.2. What devices are supported?
3.3. Which BIOSes are supported?
3.4. How can I tell if my BIOS supports ACPI?
3.5. When will my (unsupported) laptop be supported?
4. Software requirements
4.1. Which kernels are supported?
4.2. What are the latest acpi driver / supporting utilities and where can I get them?
4.3. Are binary distributions available?
5. Compilation and installation
5.1. Prerequisites and kernel setup
5.2. Useful BIOS settings
5.3. Boot parameters
6. The acpid event handling daemon
6.1. What is acpid and where do I get it?
6.2. How do I build and install acpid?
6.3. How do I use acpid?
6.4. What events will acpid respond to?
6.5. How can I keep track of what acpid thinks it's doing?
6.6. Where can I find other cool acpid scripts?
7. CPU management under ACPI
7.1. CPU management overview
7.2. CPU idle power states
7.3. CPU frequency management
7.4. CPU throttling
8. Thermal management
8.1. Overview of thermal management
8.2. What are thermal zones?
8.3. What are cooling modes and how do I change them?
8.4. What are trip points and how do I set them?
8.5. What are throttling/performance state limits and how do I use them?
9. ACPI generic hotkey driver
9.1. What is the generic hotkey driver and how do I use it?
9.2. How can I tell if my laptop supports the generic hotkey driver?
9.3. How can I get the ACPI event number for my hotkey?
9.4. How do I set up a hotkey function?
9.5. What are the hotkey driver event numbers?
9.6. What should acpid do after I press a hotkey?
9.7. Where do I find ACPI bus names and device paths?
10. Suspend to RAM
10.1. How do I suspend to RAM?
10.2. My video isn't working; what now?
10.3. What utilities are there that I can use for this?
10.4. How about suspend to RAM when I close my laptop?
10.5. My usb/pcmcia/other device doesn't work when the system resumes; what can I do?
10.6. Suspend to RAM just doesn't work after everything I've tried; what now?
11. Suspend to disk
11.1. How do I suspend to disk?
11.2. Which should I use, swsusp1, swsusp2, or swsusp3?
11.3. What utilities are there that I can use for this?
11.4. My usb///other device doesn't work when the system resumes; what can I do?
11.5. Suspend to disk just doesn't work after everything I've tried; what now?
12. Vbetool
12.1. What is vbetool and where do I get it?
12.2. How do I build vbetool?
12.3. How do I use vbetool?
13. Patches
13.1. SATA driver
13.2. Radeonfb patches
13.3. VGA post
13.4. Ethernet cards
13.5. Yenta CardBus socket
14. Debugging tips
14.1. The driver isn't working right for me. How can I figure out what's wrong?
14.2. DSDT editing
14.3. Last ditch efforts
14.4. Submitting useful bug reports
15. Extracting ACPI tables with pmtools
15.1. Compilation and installation of pmtools
15.2. Using pmtools
16. ASL compiler / AML disassembler iasl
16.1. What is iasl and where do I get it?
16.2. How do I build iasl?
16.3. How do I use iasl?
17. dmidecode
17.1. What is dmidecode and where do I get it?
17.2. How do I compile and install dmidecode?
17.3. How do I use dmidecode?
18. ACPI details
18.1. What are all these power states C1, S4, D3, etc?
18.2. What are all these ACPI tables, DSDT, FADT, and so on?
19. Other information sources
19.1. Mailing lists
19.2. ACPI on Linux laptops
19.3. Other HOWTOS
19.4. Useful papers
19.5. Official specifications
19.6. ACPI on x86_64 and other architectures
20. CPU_FREQ reference
20.1. CPU frequency managers
20.2. CPU frequency drivers
20.3. How do I regulate my CPU frequency?
21. Kernel configuration reference
22. Boot parameter reference
23. Sysfs entries reference
23.1. Overview of /sys entries
23.2. Power entries in /sys
23.3. Hotpluggable devices and /sys entries
23.4. CPU power states (C-States) and /sys entries
23.5. CPU frequency management and /sys entries
23.6. ACPI namespace tree and /sys
24. Proc entries reference
24.1. Overview of /proc entries
24.2. Wake on RTC alarm entry
24.3. ACPI info entry
24.4. DSDT entry
24.5. FADT entry
24.6. Event queue for acpid
24.7. Embedded Controller entry
24.8. Battery info
24.9. Button entries
24.10. Fan control
24.11. Power resources
24.12. CPU entries
24.13. Sleep (deprecated)
24.14. Thermal zone info
24.15. Video adapter and display entries
24.16. Wake capabilities
25. Modified acpixtract

1. About this document

1.1. Introduction

ACPI, which stands for Advanced Configuration and Power Interface, is the successor to APM (Advanced Power Management). The specification provides for many functions besides power management, such as thermal management and plug-and-play events. This document covers those functions supported by Linux to-date. This document describes how to compile, install, and use the ACPI driver for Linux and its associated applications.

I test ACPI on a 32-bit x86 system, so this document is biased towards that hardware. In particular, I do not discuss the ARM or x86_64 implementations at all, SMP systems, nor ACPI on embedded systems. For information on those topics, see the links in ACPI on other architectures.

The current Linux kernel is 2.6.14-rc4. This document covers configuration, installation, patches and problems for2.6.14-rc3 except for swsusp3, which has been tested only for 2.6.14-rc4. Some options or capabilities discussed here may not be available in earlier 2.6 or 2.5 series kernels. For information about the (early) 2.4 kernel series, please check the previous EXTREMELY old version of this document, at http://www.columbia.edu/~ariel/acpi/acpi_howto-01e.txt.

The current version of this document can always be found at http://www.columbia.edu/~ariel/acpi/acpi_howto.html. You can also find other formats of this document at http://www.columbia.edu/~ariel/acpi/.


1.2. Copyright and License

This document, ACPI HOWTO, is copyrighted (c) 2005 by Ariel T. Glenn. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2, or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is available at http://www.gnu.org/copyleft/fdl.html.

Linux is a registered trademark of Linus Torvalds.


1.3. Disclaimer

This document is provided ``AS IS'', with no express or implied warranties. No liability for the contents of this document can be accepted. There may be errors and inaccuracies that could be damaging to your system. The author(s) do not take any responsibility; use the concepts, examples and information at your own risk.

All copyrights are held by their by their respective owners, unless specifically noted otherwise. Use of a term in this document should not be regarded as affecting the validity of any trademark or service mark. Naming of particular products or brands should not be seen as endorsements.


1.4. Credits/Contributors

I've been paying great attention to the postings of Len Brown, Matthew Garrett, Pavel Machek, Jon Smirl, Li-Ta Lo, and Carl-Daniel Hailfinger. Dave Jones' posts got me through swsusp with swap on LVM on Fedora. Emma Jane Hogbin nagged me last year to get back to work on this stuff so I finally did. The City of Oakland kindly provided money for this laptop (lawsuit settlement, that's another story). Greg Michalec is loaning me hardware to test suspend on ATI Radeon hardware. My housemates endured long days of obscure rambling about these topics. Thanks to everyone.


1.5. Feedback

Please send suggestions, complaints or comments about this document to ariel@columbia.edu. Please do NOT send me bug reports about the driver; see Submitting useful bug reports for more information on reporting ACPI bugs.


1.6. [FIXME]s

This document is a work in progress. Since it's been 4 years since I updated this, there has been a lot of catching up to do. I have left some sections blank and they'll get filled in Real Soon Now. Other sections are marked with the warning [FIXME] which tells me I have more work to do on that section, and it tells you that you should be extra careful when using information from that section. Thanks for your patience.

  • I heard rumors that the earlier nVidia X drivers, version .6xxx, may suspend to RAM properly where the .7xxx series does not. I need to test this.

  • I have not worked with the Radeon patches, though a friend of mine has generously offered to let me borrow his hardware to do some testing.

  • If there are utilities for suspend to RAM/disk or additional notes on suspend on lid close, I should add them, or remove those sections.

  • Some kernel CONFIG options have yet to be documented, and explanations of a few of the boot parameters are incomplete.

  • I need to add pointers to information for ACPI on other architectures, especially 64-bit platforms. First, there needs to be some information. *sigh*

  • The description of the /proc interface for the video driver is almost nonexistent.

  • There should be more examples of acpid event handling scripts.

  • Clean up and fill out documentation of how to trigger debugging for select pieces of acpi/suspend/hotkeys drivers.

  • Write up polling method for hotkeys driver.

  • Document how to do suspend to disk with raid. [How can I do this without testing?]

  • Fill out the comparison for the various suspend to disk patchsets.

  • Detail more steps for debugging when suspend to disk doesn't work.

  • Test and document suspend to file with swsusp2.


2. Overview of ACPI

2.1. What is power management?

Power management is a catch-all term for functionality that lets you conserve power or use power resources for your computer more efficiently. For example, you may wish to reduce the brightness of your LCD panel when you're running your laptop off of batteries, or you may want your CPU to run in a lower power state if it's idle, or you may want the system to hibernate after 20 minutes if you haven't been typing. All of these are examples of power management.

These days, power management includes support for things like automated system wakeup at a given time, switching video displays, and monitoring fan speed or chipset temperature. Eventually it will probably grow to replace the desktop OS. (Just kidding...)


2.2. What is ACPI?

ACPI, or Advanced Configuration and Power Interface, is a set of specifications for power management functions of devices and the OS interface to them. It consists of descriptions of power specifications for classes of devices that describe which power states and what other functionality a class of devices must support, the definition of AML, an interpreted language for describing these various functions, and a description of how the OS calls these functions and in what context.

You may want ACPI if you are running a laptop and power conservation is a big concern, or if you want to put your desktop system to sleep during inactive periods, or if you want to monitor the temperature of various chipsets and to increase or decrease fan speed depending on those temperatures. You may want it so that you can shut your laptop lid, take your laptop to work, and open it up again, ready to go at the touch of the power button. And your computer vendor may expect you to be using ACPI so that the OS will take appropriate action if the CPU or other chipsets get too hot.

But I prefer to think of ACPI not as an optional add-on component but as an integral part of your system; in today's world, where we are all conscious of our energy use and we don't think twice about turing off the light switch when we leave a room, enabling basic ACPI functionality is common sense.

In very specific cases you may be required to enable ACPI for your system to function properly. 64-bit Itanium platforms require this; you won't get a choice in the kernel configuration menu to choose it or not, it will just be done for you. NUMA-enabled systems often require it, and systems with new Intel processors that support hyperthreading require it because they use ACPI tables for virtual processor discovery.


2.3. What is the difference between ACPI and APM?

APM, or Advanced Power Management, is the predecessor to ACPI. It required the BIOS to handle all power management. Devices were put into lower power states based on device activity timeouts. Only standby and hibernate system sleep states were supported. Some power management features such as reducing power usage of various devices when switching from ac adapter to battery were not implemented because this would have required building support for more power states and for various power usage policies directly into the BIOS. Adoption of the ACPI standard started in 1997 when developers understood that putting most of the code in the OS would allow for more features and greater flexibility. Version 3.0, the current ACPI specification, was released in 2004.

The Linux APM driver is very stable. It supports standby and hibernation, but some newer systems may not have support for APM in the BIOS at all. Although APM support in the kernel is very mature, patches still come in once in a while. ACPI, by contrast, is under furious development. A feature may be broken in one release, work in the next, and disappear completely in the next. This is no joke. As I type this, the latest FC4 kernel (2.6.12-1.1447_FC4) has suddenly made the /proc/acpi/button directory disappear; acpid relies on this to do the right thing (TM) when you close or open your laptop, or press the power button on resume. It was there in the previous version; an overaggressive patch in 2.6.13-rc5 made it go away.


2.4. What ACPI capabilities are supported under Linux?

As of kernel 2.6.13, you can do the following (if you are lucky):

  • Suspend to RAM (S3 power state)

  • Suspend to disk (S4 power state)

  • Enter standby (S1 power state)

  • monitor your battery and set an action to take on low charge

  • monitor CPU temperature and set actions to take when it gets too hot

  • monitor CPU speed, throttle your CPU, and put your CPU into different power states

  • monitor and turn on or off your fan

  • change your video display brightness, or enable an external video display

  • Set an action to take when you close your laptop

  • Set an action to take when you press the power or sleep button

  • Set your system to wake on a certain event

  • And much more to come!

Not all of these may work depending on what your particular hardware/BIOS setup supports and on the state of linux support for that hardware.


3. Hardware requirements

3.1. What hardware is supported?

Older systems have only APM support. In general, if you are working with hardware that is older than 1997, it will not have ACPI support, and if it's older than 2000, it will have only limited support.

Support for modern ATI and nVidia video chipsets is spotty under Linux. Older video chipsets tend to have better support. Cards based on the ATI Radeon have support with workarounds. This is very dependent on the version of X you happen to be using, and on the version of any X proprietary driver as well. [FIXME should test with earlier .6xxx nVidia to see if suspend works, just for shits and grins]

For comprehensive lists of laptops, their configuration, and their functionality under ACPI in Linux, see ACPI on Linux laptops.


3.2. What devices are supported?

Suspend/resume for SATA devices is not working well yet. Jens Axboe has a patch that will help for some users; see the SATA driver section for more.

Brightness controls for LCD panels is sometimes not controllable by ACPI; often, the vendor uses some proprietary method, having the BIOS adjust brightness directly when certain hotkeys are pressed. In this case you are liable to see odd messages in your log like these:

        kernel: atkbd.c: Unknown key pressed (translated set 2, code 0x85 on isa0060/serio0).
        kernel: atkbd.c: Use 'setkeycodes e005 <keycode>' to make it known.
      

Various ethernet cards have problems, but there are patches. See the Ethernet cards section for more.

ATI Radeon cards usually need help for suspend to RAM. See the RadeonFB patches section for more. [FIXME and see if this helps X].

See also the note above about supported hardware for information about other video devices.


3.3. Which BIOSes are supported?

Any BIOS that claims to support ACPI can be used under Linux. In practice, BIOSes older than 2001 that claim to have ACPI support are often broken. Current BIOSes are often broken too because they have broken DSDT tables or missing ECDT tables.

If your DSDT is buggy, in the best case, Linux ACPI functionality will be enabled but some functions will not work; in the worst case, your system may freeze. Fortunately, there is often a workaround available. See DSDT editing for more information.

If your ECDT is missing, there's a boot parameter, acpi_fake_ecdt, which can help you. See Boot parameters reference for more information.

Some BIOSes are known to be broken and they are included in a blacklist in the ACPI driver. Systems with those BIOSes at this writing are:

  • Compaq Presario 1700

  • Sony FX120, FX140, FX150M

  • Compaq Presario 800, Insyde BIOS

  • IBM 600E

  • all systems with ASUS P2B-S BIOS


3.4. How can I tell if my BIOS supports ACPI?

The most reliable way to tell is to boot with an ACPI-enabled kernel and look for ACPI messages in the log. You should see at least


        kernel: ACPI: Interpreter enabled
      

and messages like this if you have PCI slots:


        kernel: ACPI: PCI Interrupt 0000:00:1d.7[A] -> Link [LNKA] -> GSI 11 (level, low) -> IRQ 11
      

If you see messages like this:

	ACPI: System description tables not found
	ACPI-0084: *** Error: acpi_load_tables: Could not get RSDP, AE_NOT_FOUND
	ACPI-0134: *** Error: acpi_load_tables: Could not load tables: AE_NOT_FOUND
	ACPI: Unable to load the System Description Tables
      
then your BIOS does *not* have ACPI support.

If you want other ways to check your system, you can look at your BIOS settings; many systems have ACPI-related options in their BIOS menus, though not all. For example, the Dell XPS Gen 2, while fully ACPI-compliant, has no mention of ACPI in the BIOS settings at all.

You can also run acpidump, which is packaged with most distributions. To run it, be root and at the command prompt, type acpidump.

If your system is ACPI-compliant, acpidump should print out a long list of tables and their contents, including the RSDT and the DSDT. If you don't see a line something like

        DSDT @ [some hex address here]
      
you may have a problem. If acpidump produces no output, it probably has failed to find any tables. Check the exit code; if it's 0x0005 then you (probably) don't have ACPI support at all.

If you want to look through memory yourself, and you have 32-bit hardware which is not EISA/MCA based, you could try looking for "RSD PTR" in 0e0000h through 0fffffh by grepping it out of /dev/mem, like this:

        # dd if=/dev/mem of=blot bs=64K skip=14 count=2
        # od -c -A x blot | grep 'R   S   D'
        01c9b0   R   S   D       P   T   R     312   D   E   L   L          \0
      

If you see output like this, you know you have the root table stricture for ACPI, which means that you have at least some degree of support.

Note that none of these methods guarantee that the BIOS support for ACPI is bug free, just that it exists.


3.5. When will my (unsupported) laptop be supported?

If the problem is related to the video card, and you're using a proprietary driver, the outlook is not good. It depends however on your particular card and BIOS. If posting your video card after resume helps your problem, then eventually that will be fixed because sooner or later that code will make it into X or into the kernel. It's also possible that your video card vendor may provide X drivers that do the proper card reinitialization at some point.

If the problem is related to hotkey support, some laptops have specific hotkey drivers, but a generic hotkey driver is available which you should check out as well. See the Kernel configuration reference for the CONFIG_ACPI_HOTKEY option.

Detailed bug reports are extremely helpful, as are volunteers to do testing and debugging on their hardware. See Debugging tips to get started.


4. Software requirements

4.1. Which kernels are supported?

All Linux 2.6 kernels and the current 2.4 series have ACPI support out of the box. If you are running one of the 2.2 series, you are out of luck. Not all new features from 2.6 are backported into the 2.4 series kernels. Your favorite distribution probably has ACPI support turned on by default. Checked for: Fedora Core x; Suse 9.x; Debian 3.x, Ubuntu, Gentoo.

If a feature doesn't work for you in one kernel, try the next one, or even an rc intermediate release, because so much changes from one week to the next.

For the very latest in ACPI support, however, you should build your own kernel and look at the most recent ACPI patches, as there is much hard work being done on this subsystem. The most recent patches can be found at ftp://ftp.kernel.org/pub/linux/kernel/peple/lenb/acpi/patches/release/.


4.2. What are the latest acpi driver / supporting utilities and where can I get them?

Basic ACPI support is included in the linux kernel. You need acpid if you want to capture ACPI events and take certain actions based on those events. You do not need to use acpid if you want to do suspend to RAM or suspend to disk and you are willing to run a script by hand or work directly with the sysfs interface. If you want to be able to shut down cleanly by pressing the power button, you should use acpid; in addition, if you want to hibernate or suspend on laptop lid close, you need acpid. See the acpid event handling daemon to learn how to build and use it.

Here are some of the userspace utilities for ACPI power management. You don't have to use any of them to get ACPI functioning, but they can be much more convenient than accessing /proc/acpi or sysfs directly. This is not meant to be a comprehensive list. However, if you know of an application that is currently maintained and that you think should be on this list, let me know.

  • acpitool -- command line utility to get battery/fan/temperature/cpu information or to suspend to RAM/disk, turn on/off fans, and control wakeup capable devices

  • battstat-applet-2, bbacpi, wmacpi -- battery monitoring

  • wmpower, yacpi -- battery, temperature and other monitoring

  • powersave, with front ends kpowersave, gkrellm-powersave, wmpowersave -- all purpose utility covering APM, ACPI and other power management features

  • xrg -- all purpose monitor that watches everything from CPU activity and battery status to the weather and stock market data


4.3. Are binary distributions available?

All major distributions come with ACPI support built into the kernel by default. Fedora ships out of the box with acpid and battstat-applet-2, Debian has acpid and wmacpi, Suse has acpid and powersave, and Gentoo has acpid and quite a number of monitoring/power management utilities. Check your distribution's documentation to see what prepackaged options you have.


5. Compilation and installation

5.1. Prerequisites and kernel setup

To build your own kernel with ACPI support, you need the following:

Make sure that you're building with the appropriate version of gcc (at this writing, at least version 3.2).

Turn on these configuration options for base ACPI support: CONFIG_PM, CONFIG_ACPI and CONFIG_PNPACPI.

For ACPI control of some basic devices, set these: CONFIG_ACPI_AC, CONFIG_ACPI_BATTERY, CONFIG_ACPI_BUTTON, CONFIG_ACPI_VIDEO, CONFIG_ACPI_FAN, CONFIG_ACPI_PROCESSOR, and CONFIG_ACPI_THERMAL.

For suspend to RAM, set CONFIG_ACPI_SLEEP, and for suspend to disk, set CONFIG_SOFTWARE_SUSPEND, and also supply the name of the partition reserved for writing suspend data to CONFIG_PM_STD_PARTITION. NOTE: if you are suspending from something other than a standard swap partition, read the Suspend to disk section because you may want to set CONFIG_PM_STD_PARTITION to "".

For more details on these config options or for the other kernel configuration options for ACPI, see the Kernel configuration reference.


5.2. Useful BIOS settings

Most ACPI-capable BIOSes have settings that the user can tweak for power management. For example, recent versions of the AMI BIOS have an entire section for ACPI settings, including ACPI-Aware OS, ACPI 2.0 compliance, BIOS->AML ACPI table, all of which should be enabled; Suspend to RAM support, and Repost video on S3 resume which may be useful if your video doesn't come back after resume from suspend to RAM. Check your BIOS to see what power management features it offers you.

If you see APM settings in your BIOS you can ignore those. As long as you have ACPI built into your kernel and enabled, the APM settings will not be used.


5.3. Boot parameters

You should not need to pass any special boot parameters once ACPI is built into the kernel. If you run into problems, or you have special requirements, check the Boot parameters reference for a comprehensive list.


6. The acpid event handling daemon

6.1. What is acpid and where do I get it?

Older versions of acpid used to act as an intermediary between the kernel and the BIOS, looking up hex values that could be used to invoke certain sleep types and installing sleep methods; it also used to provide battery information and it had the entire AML interpreter in it. But it didn't support suspend to disk or suspend to RAM.

These days, the entire interpreter for AML now lives in the kernel. I stopped maintaining this document shortly after that patch (http://www.linuxhq.com/kernel/v2.4/3-ac8/acpi-20010413.diff) got accepted about 4 years ago. It singlehandedly added around 72000 lines of code to the kernel. One developer [fn1] is pretty sure that ACPI was designed by a bunch of monkeys on LSD, but if it had, it would at least be visually appealing. And this ain't.

OTOH, the acpid daemon has become much simpler. It now watches for all acpi-generated events and allows the user to define the appropriate action to take on receiving those events.

Most distributions come with acpid out of the box. If you want to build your own, you'll find the latest version at http://sourceforge.net/projects/acpid/

[fn1] See http://lkml.org/lkml/2005/7/31/219.


6.2. How do I build and install acpid?

Make yourself a build directory and untar the file: zcat acpid-1.0.4.tar.gz | tar xvfp - cd into the directory: cd acpid-1.0.4

If you download the tarball, edit the Makefile if you're using gcc 4.x: change the line CFLAGS = -Wall -Werror -g $(DEFS) to read CFLAGS = -Wall -g $(DEFS) (This is fixed in cvs.)

build it: make install it: make install This puts acpid in /usr/sbin and acpi_listen in /usr/bin It also installs the man pages.

These programs use /proc/acpi/events (boo). When will they use /sys?


6.3. How do I use acpid?

Linux sees ACPI events, in some cases takes an action, and then writes a description of the event to /proc/acpi/events so that userspace applications can take actions as well. Acpid watches /proc/acpi/events and, for every event logged there, looks at its set of rules to see what action(s) to take. These actions are specified by you, the user.

Acpid looks for its rules by default in /etc/acpi/events at all files in that directory (no subdirectory walking though). Each file in there is expected to contain rules that tell acpid what to do on each event.

Each file may have blank lines or comments starting with # Then you must include at least one line defining an event and one line defining an action.

Here's an example:


      # This is a sample ACPID configuration

      event=button/power.*
      action=/sbin/shutdown -h now
    

That file ships with Fedora Core 4 and tells acpid to shut down when the power button is pressed (so you don't have to give the three-finger salute).

%e and %% are special strings; if you use %e in the event description or in the action description, the full text of the event as described in the previous section will be substituted into the string, and if you use %% in either description, the character % will be substituted in. If you use % in any other combination, you'll get an error.

You can define multiple actions for the same event, but they won't necessarily be processed in the order you list them in the file.

You can also put multiple event lines in one file and use the same action for all of them. [FIXME examples would be nice]

If you have acpid source from CVS or tarball, you can look at more interesting examples such as the battery.sh script which is intended to be used from one of these rule files. It reacts on any battery event, checks to see whether the system is on AC or battery, and sets or disables hard drive spindown time appropriately. Note that this script may not work for you out of the box, as your AC adapter may have a different name (mine is called /proc/acpi/ac_adapter/AC); it's here as an example only.

On FC4 you are expected to put all your fancy scripts into /etc/acpi/actions but nothing in the acpid code requires this. Put them where you want.


6.4. What events will acpid respond to?

It is not possible to provide a comprehensive list, because the list of events depends on your vendor's hardware and their ACPI implementation. However, it is possible for you to figure out what events will be issued on your hardware by looking at /sys/firmware/acpi and collecting some information.

First, let's see what an event looks like. If you are running acpid, and you are running ACPI with any applet to monitor battery status of control cpu speed, you can look in /var/log/acpid at events it has received. You may see messages like this:


      completed event "processor CPU0 00000080 00000004"
      received event "ac_adapter AC 00000080 00000001"
      received event "battery BAT0 00000080 00000001"
      received event "button/power PBTN 00000080 00000001"
    

Each event as logged consists of the device class name, the bus id name, the event type, and the event data. Device class names are standardized, and you can get the list by looking for all #defines of "CLASS" in the kernel code in drivers/acpi. My list is:

ac_adapter, battery, button, container, embedded_controller, fan, Hotkey (because the asus driver got the word "hotkey"), lid, memory, pci_bridge, pci_irq_routing, power, power_resource, processor, sleep, system_bus, system, thermal_zone, video

Note that some of these are subclasses; power, sleep and lid are subclasses of button, and they'll get written as button/lid, button/power and button/sleep in the log.

Bus IDs are not standardized; they are defined in a vendor's implementation. Fortunately, the names vendors use are similar and usually recognizable.

You can find out which Bus IDs your vendor is using on your current hardware by looking in /sys/firmware/acpi/namespace/ACPI/. My system shows


      ls /sys/firmware/acpi/namespace/ACPI/
      CPU0  CPU1  _SB  _TZ
      ls /sys/firmware/acpi/namespace/ACPI/_SB
      AC  BAT0  LID  MB1  PBTN  PCI0  SBTN
      ls /sys/firmware/acpi/namespace/ACPI/_SB/PCI0/
      AGP  AUD  IDE0  ISAB  LNKA  LNKB  LNKC  LNKD  LNKE  LNKF  LNKH  MB2  MB3  MODM  PCIE  USB0  USB1  USB2  USB3  USB4
    

You may decide you don't need to know what the event type is; for example, if you get a battery event, you might look at /proc/acpi/battery/BAT0/info (or BAT1/state, or whatever your battery device is called), check the remaining capacity and take any appropriate actions.

However, there is a list of event types in the ACPI specification. Here's the summary:

For all devices, 0 = bus check (time to rescan the bus); 2 = device removed or added; 3 = device awakened; 4 = device eject, 5 = device removed or added ("device check light", don't ask me what the difference between this and 2 is); and some other events that you probably won't care about as a user. See page 142 of the specification if you want the rest.

For specific devices:

Battery: 0x80 = battery status changed, 0x81 = battery information has changed (i.e. you have a different battery in there now); 0x82 = check battery maintenance flags.

Power source: 0x80 = power source status changed. (Think AC adapter.)

Thermal zone: 0x80 = thermal zone temperature changed; 0x81 = thermal zone trip points changed; 0x82 = thermal zone device lists changed; 0x83 = values in thermal relationship table changed

Power button: 0x80 = power button pressed. Warning: If the power button is pressed with the system in S1 through S4, you will not see this event; instead you will see a Device Wake (0x02)!

Sleep button: 0x80 = sleep button pressed. Warning: If the sleep button is pressed with the system in S1 through S4, you will not see this event; instead you will see a Device Wake (0x02)!

Lid: 0x80 = Lid status changed (either open or closed).

Processor: 0x80 = number of supported processor performance states (P states) has changed; 0x81 = number or type of supported power states (C states) has changed; 0x82 = number of supported throttling states has changed.

video (part 1): 0x80 = state of one of the displays attached to the graphics adapter has been toggled; 0x81 = re-enumerate all devices on the adapter (i.e. a device has been added or removed); 0x82 = cycle display output (next display activated and if the last one was active then the first one now is); 0x83 = next display activated; 0x84 = previous display activated. Note: for these events, when a new display is activated, Linux deactivates the previously active one. If you want more than one display to be active, you should activate them by using the /proc/acpi/video/VID/*/state interface. See Proc entries reference for the /proc entries. Also, I'm unsure if cycling the display output really should put you back to the first device if you are at the end of the list; at least, Linux doesn't appear to do this, from a quick scan of the code.

video (part 2): 0x85 = display brightness increased one level and if it was at max, it got set to min level; 0x86 = display brightness increased one level and if it was at max, it stayed there; 0x87 = display brightness decreased one level and if it was at min, it stayed there; 0x88 = display backlight turned off; 0x89 = display off WARNING: these values are right out of the ACPI 3.0 spec. But they are not the values Linux uses! It uses: 0x82, 0x83, 0x84, 0x85, 0x86 for each of these things in order. Uh oh... I don't have (ACPI) brightness control support, so I can't test this to see what should happen. Anybody?

Some events that Linux passes on are not defined in the spec; that is, I can't find a table with numbers for these. I got the values by looking for invocations of acpi_bus_generate_event() in the kernel acpi driver code, and checking the event passed in that function.

thermal zone: 0xf0 = critical temperature trip point is being passed which requires immediate shutdown; at this point Linux will shut down by calling /sbin/poweroff. You don't really have much time to process this event. :-) 0xf1 = critical temperature trip point is being passed which requires the OS to put the system into S4 (hibernate) if that state is supported. The Linux kernel does not yet do this. It has a comment placeholder where the code ought to go.

If you use the generic hotkey driver (CONFIG_ACPI_HOTKEY), then when you press an authorized hotkey, you'll get an event sent to /proc/acpi/events for it. That list is described in How do I use the hotkey driver?

No, I'm not documenting the state data; look it up your own darn self :-)


6.5. How can I keep track of what acpid thinks it's doing?

Acpid logs all of its activity to /var/log/acpid by default. Check your init scripts to see where your distribution directs its logging.

You can also run acpi_listen. This command will connect to acpid and write every event that acpid sees to stdout, in exactly the format the event appears in /var/log/acpid, but without the extra commentary.


6.6. Where can I find other cool acpid scripts?

A few nice Thinkpad scripts can be found at http://www.thinkwiki.org/wiki/Category:Scripts

Unfortunately, scripts are very dependent on your particular hardware configuration.

Some folks have put up acpid scripts on their pages describing the installation of some distribution on their laptop. Check these resources for more information.


7. CPU management under ACPI

7.1. CPU management overview

ACPI gives you unprecedented control over your CPU's power consumption. You can control power usage in three different ways: setting idling power states, changing cpu frequency, and throttling the CPU.


7.2. CPU idle power states

First, the CPU can enter different idle power states, C1 through Cn (usually C1 through C4). If a processor is in state C0, it is working normally; in any other state, it is idle (doing no work). Lower power states use less power but the CPU will take longer to transition to a higher power state. So if your CPU is in C4 it will use less power than in C3 but it will take longer to come out of idle than from C3.

You don't have to do anything to make the CPU go into the appropriate idle state; the kernel will place the CPU into a lower power state automatically when it is not busy. However, you do need to build this capacity into the kernel by enabling CONFIG_ACPI_PROCESSOR. See the kernel configuration reference for the CONFIG options.

You can look at the /proc/acpi/processor/power file to see how long your CPU spends in each state; see Proc entries reference for more on this file. You can also look at /sys/module/processor/parameters/max_cstate to see what the lowest power state the kernel will give you is; see Sysfs entries reference for more on that.

And you can adjust max_cstate by using the processor.max_cstate boot parameter. In some cases machines that enter C3 or C4 produce a loud whine, and you may want to limit your system to C1 and C2. In some cases you may want your system to enter C3 or C4 but it's been blacklisted by the kernel and limited to C2; you can use this same parameter to override the blacklist. See Boot parameter reference for details.


7.3. CPU frequency management

Second, you can also run the CPU at lower frequencies when it isn't doing so much work. If you're spending most of your time typing text instead of compiling, this can be very useful for power savings. In ACPI lingo, the CPU enters various P-States, P0 through Pn, where at P0, the CPU is running at its highest frequency and at Pn it runs at a lower frequency the greater the value of n. These performance states are only valid when the CPU is in power state C0; the rest of the time the CPU is in some idle state and so adjusting its clock frequency doesn't make any sense.

To benefit from this, you'll need to enable CPU frequency control by setting CONFIG_CPU_FREQ. Then you can choose which of several performance managers to build in; these adjust the frequency based on different criteria. Then you can choose which hardware-level driver to build in. Only certain of these drivers support ACPI P-States; the rest use a proprietary method of regulating CPU frequency and are not discussed further in this document. Further, of those that use the designated P-States, only the ACPI P-States driver (CONFIG_X86_ACPI_CPUFREQ) actually notifies the ACPI subsystem of P-State changes. If you think this is confusing, you're right.

After your kernel is set up, you can either use one of several userspace applications to automatically set your CPU to a lower frequency depending on the load, or you can use an applet that lets you set the frequency manually as you desire, or you can use one of the performance managers that adjusts frequency for you in kernel space. For all the details, see CPU_FREQ reference.


7.4. CPU throttling

Third, you can throttle your CPU. This means that you force the cpu to be idle a fixed percentage of its cycles per second. Throttling states are called T1 through Tn, where in T1 the CPU has no forced idle cycles, and the percentage goes up the greater n is. For example, on my system, T4 forces the CPU to be idle for half of the cycles.

This is different from changing the frequency, which makes the cpu have fewer cycles per second, and it's different from running in a C state other than C1, because those are states where the CPU is idle for all cycles.

If you have a certain amount of work to get done, then throttling the CPU will cause the work to take longer to get done. However, if temperature is a concern, then this will keep your CPU running cooler.

Note that this does not reduce voltage, and since all tasks will take longer (since the CPU is forced idle part of the time), you actually use more power to get any given task done. This is in contrast to CPU frequency management; when the CPU frequency is lowered, voltage is lowered too, and any given task should draw less power unless it requires the CPU to run full out for the duration of the task.

You can check which throttling states are supported by your CPU by looking at /proc/acpi/processor/CPU*/throttling. This file will also show you what percentage of idle time each state enforces. You can set the current throttling state for your CPU by writing the state number to /proc/acpi/processor/CPU*/throttling. Read it back to make sure the change works; if it doesn't, you may have a bug in your DSDT or elsewhere.

Note that throttling states only work when the CPU is in the power state C0. But they work for any performance state (P-state); this means that no matter what frequency the CPU is running at, you can still do throttling. For information on how to do this, see Thermal management.


8. Thermal management

8.1. Overview of thermal management

ACPI provides several means for monitoring and controlling system temperature. Via thermal zones, you can adjust the system cooling mode when it's too hot, you can turn on and off fans when you reach certain temperatures, and you can throttle your CPU when it gets too hot, taking into account the performance state it's running in. Not all platforms support all of these features, but the ACPI 3.0 specification provides all of these mechanisms.


8.2. What are thermal zones?

If your vendor's implementation of ACPI supports thermal management, you'll have one or more thermal zones, which you can monitor by checking /proc/acpi/thermal_zone for these devices. They'll be called something like THM or THRM0.

I haven't seen a system with multiple thermal zones. Typically a system has one big thermal zone which includes the entire interior region of the case. Practically speaking, it must be connected to a sensor somewhere, probably by the CPU.

Linux should poll the temperature every so many seconds. In practice, however, Linux tries to figure out how often to poll by invoking the _TZP method, which many vendors don't provide. When that fails, Linux disables polling altogether. Fortunately, you can enable it by echoing a number to the file, for example, echo 30 > /proc/acpi/thermal_zone/*/polling_frequency, to have Linux check the temperature every 30 seconds.

You can monitor the temperature for each thermal zone yourself by reading the file /proc/acpi/thermal_zone/*/temperature.


8.3. What are cooling modes and how do I change them?

A cooling mode is a description of how your system is cooled in a certain temperature range. Your cooling mode can be critical, passive, or active. Active cooling means that a fan or other cooling device can be turned on when the temperature passes a critical point. Passive cooling means that devices can be put into a lower power state when the temperature is too hot. Critical cooling means that when the temperature passes one trip point, the so-called "hot point", the OS will transition into S4 (suspend to disk) if possible, and if the temperature passes a second trip point, called the "critical point", the OS will shut down the system.

If your platform supports it, Linux will set the cooling mode to active by default. If this isn't successful, but both active and passive modes are supported, then the cooling mode which supports the lowest trip point is the one in use. If only one of passive or active cooling modes is supported, Linux will use that. Failing that, it will fall back to critical cooling mode, which must be supported by your vendor.

Some platforms allow you to change the cooling mode. You can do this by echoing 1 to /proc/acpi/thermal_zone/*/cooling_mode to set passive cooling, or 0 to /proc/acpi/thermal_zone/*/cooling_mode to set active cooling. Critical cooling will always be active, in case your system heats up so much that drastic measures must be taken, even with fan use or power reduction.


8.4. What are trip points and how do I set them?

Trip points are set temperatures that, when the system temperature reaches them, trigger some sort of action. Typically this can be a change in cooling mode, or something more drastic. The critical cooling mode has two predefined trip points. If the system reaches the first one, called the "hot point", Linux will try to put the system into S4 (suspend to disk) if possible, and if the temperature passes the second one, called the "critical point", Linux will call /sbin/shutdown -h now.

You can define multiple trip points each with their own cooling policy. If you do, they'll show up in /proc/acpi/thermal_zone/*/trip_points like this:

	critical (S5): 100 C
	passive: 97 C: tc1=4 tc2=3 tsp=40 devices=0xcf6b6d80
      

You can set critical, hot, passive, and up to 9 active trip points. Here's how you do it: echo a string of numbers to /proc/acpi/thermal_zone/*/trip_points separated by a colon. These numbers are the various trip points in Celsius. NOT IN Fahrenheit! So you *can* echo 99:80:35:75:60:55:50:45 > /proc/acpi/thermal_zone/*/trip_points to set the critical trip point at 99C, the "too hot, suspend now" trip point at 80C, the passive trip point at 35C, the first active trip point at 75C, the next one at 60C, and so on through the fifth active trip point at 45C, but in practice that's a lot of trip points. You probably only need one or two; after all, how many extra fans do you have? However, Linux expects to see at least 5 values, and if it doesn't see them it throws an error and refuses to process the change. So even if your system only does passive cooling, you must supply values for active[0] and active[1]. Just set them to 0 if they don't make sense for your platform.

Unfortunately, if you write values to trip_points (at least 5) and these other cooling methods are not supported, Linux will not inform you about it. It will silently accept the values and move on. On my system I can't even reset the lone critical trip point permitted me; but no errors are generated; the only way I can tell is to read the trip_points file again and see that it hasn't changed.


8.5. What are throttling/performance state limits and how do I use them?

These limits set the highest (highest frequency) P-State, and highest (least throttling) T-state your platform is permitted to use under certain circumstances, where P0 is a higher P-State than P1, and T0 is a higher T-state than T1. Sorry for the lousy terminology.

You can see what the current throttling/p-state limit is, by looking at the file /proc/acpi/processor/limit. Look at the active limit, which will show a performance state, like P0, and then a throttling state, like T0.

To set a limit, write two numbers separated by a colon, like "0:0" into limit. The first number is the processor performance state, and the next number is the processor throttling state. This will set the user limit, which you also see when you read that file. The active limit is chosen as the maximum of the user and thermal limit T-state numbers; i.e. if the user limit is T2 and the thermal limit is T3 then the active limit will be T3.

Unfortunately, Linux does not seem to use the first number for anything. It always uses the value of 0 to update its internal copy of what it thinks the P-State is for display in the limit file. Maybe that's ok, since it never actually sets the P-State from that value :-(

Warning, esoterica: Only the ACPI P-States cpufreq driver updates the CPU's P-States. This file could either show the actual P-State (and update it on demand) for that one driver, or it could map frequency changes from all drivers into P-States by name, and reflect the change by changing frequency according to the registered cpufreq driver. Right now it just leaves the Px value around in the limits file to be confusing to the user, the worst of both worlds.

In any case, the second value does get stuffed into the user limit thermal value, and you can verify that by reading the file. It takes effect immediately. Note that the user limit can never be a higher (less throttling) state than the thermal limit; for example, if the thermal limit is T1, then the user limit cannot be T0.


9. ACPI generic hotkey driver

9.1. What is the generic hotkey driver and how do I use it?

The generic hotkey driver allows you to make those nifty hotkeys on your laptop work. The concept is simple; your laptop has a hotkey that Linux doesn't understand and that has no effect. You expect it to actually set the brightness of your LCD to max, for example. So, you define a function that includes the ACPI event number generated by your hotkey, the hotkey driver event number that corresponds to the function you want the key to do (here, increase brightness), information required to find the right video device, and the ACPI method name for increasing brightness. Once the function is set up, any time you press the hotkey, an event will be generated that acpid can pick up, and once you define the right rule for acpid, you'll have your hotkey working.


9.2. How can I tell if my laptop supports the generic hotkey driver?

This does not work for all laptops; your laptop must generate an ACPI event when you press the particular hotkey you want to use. This means that in your DSDT, you will have something like \_SB.PCI0.LPC.EC.HKEY.BTIN () (IBM laptops), or Name (_HID, "ATK0100") (ASUS), or Device (HKEY) (Panasonic).

If you want to know if your hotkeys generate ACPI events, one way you may test this is to turn on debugging (CONFIG_ACPI_DEBUG = y) in your kernel, boot up, echo '0xffffffff' to both /proc/acpi/debug_level and /proc/acpi/debug_layer, and then press a hotkey. Just one! Once! This will either generate a lot of error messages in your log, or none at all. If it generates none, you are out of luck. Otherwise, you should be able to use this driver. [FIXME see which parts of the debug layer we can minimally turn on to get useful messages.]


9.3. How can I get the ACPI event number for my hotkey?

You can try just pressing the key and see if anything shows up in /var/log/messages. If not, you'll have to resort to the method described above, i.e. build in ACPI debugging, turn on all debugging bits, and then slog through the log.

The event number that your hotkey generates can then be retrieved by looking for lines in your log like "ev_queue_notify_reques: Dispatching Notify(80)".


9.4. How do I set up a hotkey function?

Let's take our earlier example. Say your laptop has a hotkey that should set the brightness of your LCD to max. So, you define a function that includes the event number generated by your hotkey (which you must determine by looking at log output after pressing the hotkey), the appropriate hotkey driver event number, in this case 0x86, the ACPI bus name on your platform, the ACPI full path name for your LCD, and the AML method you are going to call, which in this case is _BCM, the AML method to control the brightness level.

On my system, if Dell actually had hotkeys implemented through ACPI, which it doesn't, I'd do the following:

	echo '0:_SB::_SB.PCI0.AGP.VID.LCD:_BCM:128:136' > /proc/acpi/hotkey/event_config
      
I've used a made-up value for the event number generated by pressing the hotkey, since Dell hotkeys don't generate ACPI events, but the rest is correct for my platform. I could then verify that the setup worked by looking in the log for errors and by reading /proc/acpi/hotkey/event_config, which would give me

	_SB_:LDD_:_DSS:128:136
      

Let's look at that in a little more detail. In the example above, we have 7 arguments, which you must always provide to add a new key. The first argument must be 0 which indicates that this is a new key definition. The second argument is the name of the bus on which your device sits that you're going to affect; the LCD panel on my system is on the _SB bus. The third argument must be omitted for event-based key definitions. The fourth argument is the full ACPI namespace path name of the device, and the fifth argument is the AML method you are going to call. The sixth argument is the event number that your key press sends to the ACPI driver, and the seventh argument is the hotkey driver event number which the driver will use to look up the event in its tables. For the seventh argument, you can use any hotkey event number you like (as long as it's known to the driver), but you may kick yourself later when you have to read your script and understand what it does.

You can also set up keys to use a polling method; I'll cover that in a future version of this document. [FIXME]

Fun fact: you don't have to map the hotkey to a method that has anything to do with the intended function of the hotkey, or with the intended meaning of the event number you chose from the hotkey driver event list. So you could map your wireless activation hotkey to turn of your fan via the _OFF control method, if your fan supports that control method. I'm not saying you should; I'm just saying you *could*.

To remove the key definition, just do echo '1:::::128:136' > /proc/acpi/hotkey/event_config where the 128 should be replaced with the actual ACPI event generated by the key press, and the 136 should be replaced with the hotkey driver event number you actually used.

To change the definition, just put the new definition to /proc/acpi/hotkey/event_config but use '2' as the first argument, which indicates that the key definition already exists and should be updated with the new values.


9.5. What are the hotkey driver event numbers?

The list, grabbed from hotkey.c, is

video (see video events above for more on what these do):

  • 0x80, cycle output device hotkey pressed;

  • 0x81, output device status change hotkey pressed (maybe it disconnects one of the devices);

  • 0x82, cycle display output hotkey pressed;

  • 0x83, activate next display output hotkey pressed;

  • 0x84, activate previous display output hotkey pressed;

  • 0x85, cycle display brightness hotkey pressed;

  • 0x86, increase display brightness hotkey pressed;

  • 0x87, decrease display brightness hotkey pressed;

  • 0x88, set display brightness to zero hotkey pressed;

  • 0x89, turn display off hotkey pressed

sound (why are these here? they aren't ACPI related):

  • 0x8a, volume mute hotkey pressed;

  • 0x8b, volume increase hotkey pressed;

  • 0x8c, volume decrease hotkey pressed

sleep states buttons:

  • 0x8d, Suspend to Ram hotkey pressed,

  • 0x8e, Suspend to disk hotkey pressed,

  • 0x8f, Soft power off hotkey pressed


9.6. What should acpid do after I press a hotkey?

Once the definition is set up, if I pressed the hotkey, an event of type "Hotkey Hotkey 0x00000086 0" would be generated, and acpid could pick it up and do the right thing with it. The right thing is already almost predefined: it should echo "136:1::100" > /proc/acpi/action where 136 is the event code that acpid was given in /proc/acpi/events converted to decimal, the "1" means it is event based rather than poll-based, i.e. the event was read from /proc/acpi/events, the third missing argument is only needed for poll-based hotkeys, and the 100 is the argument to _BCM to set the brightness to the maximum level.

The trick is that most of these methods actually don't do exactly what you want the hotkey to do. Here's a summary of the relevant AML methods from the ACPI spec.

_BCM controls brightness. Pass the number (percent of 100) to set the level to. Supported brightness levels can be retrieved by reading the file /proc/acpi/video/VID/*/LCD/brightness (or CRT, or whatever device you are checking). That means that if you have a hotkey for increasing brightness, mapping it to this method will not be enough. You should use a script that gets the current brightness, checks the supported levels, and sets the next one. That script can use /proc/acpi/action, but it will have to have figured out the right brightness level as the argument to _BCM first.

_DSS makes the display active or inactive. Pass 0x80000000 to inactivate, and 0x80000001 to activate. You can see the state of each device by reading the file /proc/acpi/video/*/LCD/state (or CRT, or whatever device you are checking). That means that if you have a hotkey to switch between CRT and LCD, mapping it to this method will not be enough. You should use a script that gets the current active device, inactivates it, and sets the other one as active.

There are no methods for sound control in ACPI; that's not really a power management feature. In order to get the sound-related hotkeys to work, you may have to have acpid run alsamixer or some such to do the right thing.

The sleep state hotkeys are another bit of a kludge. What you want to do here is to have acpid do any prep work for the suspend or power off; for suspend, you may have modules you want to remove, and so on. Then you want to actually do the suspend by echoing the right state into /sys/power/state, and finally do the right thing on wakeup, by reinserting modules and so on. For poweroff, you can have acpid call /sbin/shutdown -h now, or whatever other shutdown mechanism seems good to you. Once again, these hotkeys must be set up with placeholder bus names, device paths, and AML method names; these items are only there so that the hotkey driver will register the key definition and not throw an error.

So what this means is that in all of these cases you are going to use a script to handle the event. There is perhaps one exception: if you have a hotkey that turns off the display, or turns the brightness down to zero, you can map that directly to the appropriate method with a fixed argument. In the rest of these cases, you still have to pass a valid bus name, device path, and AML method name, so choose something harmless and then don't ever use /proc/acpi/action with it. I recommend _SB for the bus name, _SB.PBTN (or whatever your power button is called) for the device name, and _PSW for the method name, since you won't need these for anything else. This assumes your power button supports _PSW; if not you may have to look around in your DSDT yourself for some ideas.


9.7. Where do I find ACPI bus names and device paths?

Bus names are easy; see the discussion of bus names as part of events in How do I use acpid? Device paths are not easy, because device names are set by the vendor and vary from one platform to the next. You can get valid device paths for your system out of the ACPI namespace by looking at /sys/firmware/acpi/namespace/. Find the device you're going to affect somewhere in the directory tree, say LCD, and grab the full name, starting with _SB and ending in the device name. You need to put a "." instead of a "/" between directory names, so that you get something like _SB/PCI0/AGP/VID/LCD converted to _SB.PCI0.AGP.VID.LCD as the device path. Again, this is only useful in the rare case where you have a hotkey that does a fixed action (not increasing the brightness, but setting it to max/min; not switching the active display but turning one off or on).


10. Suspend to RAM

10.1. How do I suspend to RAM?

Suspend to RAM is part of the kernel. Make sure you have ACPI enabled in the BIOS and the kernel, and that you have the CONFIG_ACPI_SLEEP option set.

It's a good idea to remove all usb devices and modules, as well as any firewire devices and modules. If your suspend works well without them, try adding them back in.

Then echo mem > /sys/power/state You'll see some messages on the console about suspension, ending with

          hwsleep-0296 [08] acpi_enter_sleep_state: Entering sleep state [S3]
        
Then your system should go to sleep.

Pressing the power button should bring the system back, starting with some hard disk activity.


10.2. My video isn't working; what now?

  • Type an innocuous command such as ls and press <Enter>; some folks report that their display comes back on the first <Enter> key press.

  • If your laptop supports display brightness adjustment, and that works on your system before suspend, try using that after suspend and see if your video comes back.

  • See if switching your video display from your internal LCD to an external CRT and back brings back your video. You can do this even if you don't have an external CRT hooked up. See [] on how to do this.

  • If none of those things work, see if your system responds to keypresses. Does pressing the Caps Lock key turn the Caps Lock LED on? If not, wait about 5 minutes, and try the same activity again. Sometimes the kernel has gone out to a short snack instead of out to lunch. This works for me.

  • If you have Caps Lock responsiveness, try suspension with networking enabled, and see if your computer is pingable (again, wait 5 minutes if there is no initial response).

  • If it is, you might try again with sshd and see if you can log into the system. Then you can try some vbetool tricks to muck with the display. See Vbetool for vbetool usage and tricks.

  • If you don't have network access, see if typing sync gives you disk activity. If so, you can try the vbetool tricks mentioned above. Set up a script ahead of time so that you can minimize typing mistakes while typing blind.

  • If none of those things work, you can try a few specialized boot parameters: acpi=s3_sleep, acpi=s3_mode, or pci=routeirq. See Boot parameters reference for more information.


10.5. My usb/pcmcia/other device doesn't work when the system resumes; what can I do?

Build usb support and the specific driver support for those devices as modules and write an acpid script that removes these modules before suspension and reinserts them afterwards. Here's an example, adapted from Gentoo's wiki page on the Samsung X20 at http://gentoo-wiki.com/HARDWARE_Samsung_X20#ACPI_hotkeys:


	#!/bin/sh
	
	if [ -e /tmp/lidclose ]
	then
            echo "[" `date` "] Wakeup from standby (lid opened)" >> /var/log/acpi_events
          
            rm /tmp/lidclose
    	else
            echo "[" `date` "] Go to standby (lid closed)" >> /var/log/acpi_events
 
            touch /tmp/lidclose

            # USB Module
            rmmod uhci_hcd
            rmmod ehci_hcd

            /sbin/hwclock --systohc
            echo mem > /sys/power/state
            /sbin/hwclock --hctosys

            modprobe uhci_hcd
            modprobe ehci_hcd
	fi
      

10.6. Suspend to RAM just doesn't work after everything I've tried; what now?

Help us debug the problem. Here are some steps to take:

Rebuild your kernel with support for as few devices as possible, preferably no usb, and no pcmcia unless your network is pcmcia and you have network after you resume.

Turn off optional devices in your BIOS; my Dell laptop lets me turn off the modem and wireless devices.

Turn off the framebuffer device.

Boot as single user, turn on networking and sshd if your machine is pingable after resume, turn on syslogging, and try suspend/resume from there.

Turn off networking for good measure and try that, just to see if that has an impact.

Make sure your BIOS is the most recent possible.

Check your DSDT; see DSDT editing for instructions.

If you are running an old distribution, in particular an old version of X, update it/them. If you are using proprietary drivers, make sure you are using the most recent version.

Try suspend from X as well; video drivers don't live in the kernel except for framebuffer drivers, and the X drivers sometimes know how to reinitialize recent video cards.

Look also at Documentation/video/blot.txt for more things you can try.

If you still can't resume, get what you can from the logs and submit a bug report.


11. Suspend to disk

11.1. How do I suspend to disk?

11.1.1. Suspend to disk methods

Note: Suspend to disk is entirely independent of the ACPI subsystem. But it's included in this document because, hey, what the heck.

There are three different patches around for suspend to disk. As of this writing, the kernel has a set of patches inline, which are called swsusp and which in this document I will refer to as swsusp1. Software Suspend 2 is a set of patches not yet merged into the kernel; Software Suspend 3 is a user-space implementation still in the works. Pm-disk, which used to be yet another fork from swsusp1, was combined with swsusp1 in mid-2004.


11.1.2. How do I use Suspend to disk 1?

Make sure you have a swap partition, not a swap file, that it's on a separate physical partition, and that it's at least as big as your memory. If your swap partition is on an LVM partition, read the later part of this section; if it's on raid, there is support also [FIXME].

Back up your data before your first test. No joke! If you happen to have an unsupported driver, bad things can happen.

Get a few patches first: the data free patch at http://lkml.org/lkml/2005/9/25/86; the pagedir patch at http://lkml.org/lkml/2005/9/26/190; and the memory leak patch at http://lkml.org/lkml/2005/9/25/89. These apply to 2.6.14-rc2 cleanly.

Now, build your kernel with CONFIG_SOFTWARE_SUSPEND=y. According to gossip on the Linux kernel mailing list, CONFIG_PM_STD_PARTITION is going to be removed someday; the approved method of specifying the resume partition is to pass it as an argument at boot time. For Grub users, this means appending the argument "resume=/dev/something" to your kernel boot line, where "/dev/something" should be replaced with the full name of your swap partition.

Boot into the new kernel. If you are watching closely, or if you check /var/log/messages, you'll see that the kernel attempts to resume from your swap partition even though there's nothing to resume from (yet). This is normal behavior; your kernel will do this every time. If you see this message: swsusp: Error -6 check for resume file, it means that your swap is not on a physical partition or that you have underlying modules that need to be loaded before the partition can be found. Check that IDE and/or SCSI support is built in directly to the kernel, and try again until this message goes away.

For the first test, you might want to be root and init 3 so that X isn't running. It's also a good idea to unload usb modules, PCMCIA modules, and network/wireless modules.

Now give the following command: echo shutdown > /sys/power/disk; echo disk > /sys/power/state You will see all devices suspend and then resume again briefly; at this point the swap image will get written and you'll see a progress count. After the image is written, devices will be suspended again and then your system should power off.

If you have mice or removable devices or other hardware attached to your system, LEAVE THEM ALL AS IS. Don't change the hardware configuration at all; resume expects to resume to a system that is identical to the one it suspended to. Forbidden hardware configuration changes include plugging the the laptop when it was unplugged!

Press the power button briefly, and you will go through the normal boot sequence. Choose the same kernel from the boot menu, with exactly the same kernel arguments you gave before; if you change this, you could lose all of your data.

Once you boot, the system should resume from the image it wrote out earlier, and you'll be returned to the exact state you were in before suspension.

One thing that you may do, without disturbing the resume process at all, is to boot into a different OS, as long as you don't touch the swap partition or the other partitions that were mounted when you did the suspend. You cannot mount them from somewhere else, even if you don't touch anything after the mount. So for example, you could boot into your 64-bit version of Linux on some other disk, do work there, then reboot into the kernel from which you suspended, using the same kernel arguments as for the suspend, and you'll be back where you were at the point of suspension. Don't forget that your hardware configuration must not have changed!

On a system where your swap partition is an LVM partition, you must take a different approach. You must use initrd/initramfs. It doesn't matter whether your distribution supports the old initrd format or the new cpio format (initramfs); in either case you make the same changes, but for the old format you look at the file linuxrc in the image, and for the new format you look at the file init in the image, to add commands that enable LVM.

Build your kernel with CONFIG_SOFTWARE_SUSPEND=y. For CONFIG_PM_STD_PARTITION, set the value to "". DO NOT pass any resume= argument to the kernel at boot time or in your grub.conf. At suspend time, this will cause the kernel to look for the first swap partition it can see and use it to write the memory image. It will also cause the kernel to write this message to /var/log/messages: resume= option should be used to set suspend device. Ignore that error.

Now you must get several supporting utilities or patches to them. [FIXME other distros...]

For RedHat/Fedora, you need mkinitrd version 4.2.22-1 or later; utils-linux 2.13-0.3.pre2 or later (for updated swapon); and e2fsprogs 1.38-1 or later. You can either build these from source or get the binary rpms and install them. At this writing, these updates are only available from the rawhide (unstable) release tree, and installing the binary rpms requires installation of glibc*2.3.90-12 or later.

If you are using RH/Fedora, you can use mkinitrd to create an initrd that will support lvm and resume from your swap partition. Just run mkinitrd --allow-missing -f /boot/initrd-2.6.14-rc3.img 2.6.14-rc3, substituting the actual name of your kernel for 2.6.14-rc3, such as 2.6.13-1.1588_FC5 or whatever uname -r shows you. Mkinitrd will look for the first enabled swap partition and write the commands to make it available and resume from it into the init file in the new initrd.

If you are using another distribution which includes mkinitrd, you should check to see whether they have an updated version which supports lvm and resume from swap on a logical volume. You must use the new mkinitrd to build an initrd image that will be used when you suspend/resume.

If you don't want to use your distribution's mkinitrd or your distribution doesn't provide one, then you can build one yourself. At a minimum, it should have a statically linked version of /bin/lvm. Your init or linuxrc script should create /dev/mapper/control, run lvm vgscan --ignorelockingfailure, run lvm vgchange -ay --ignorelockingfailure VolGroup00 (you should include the volume groups that contain your rootfs and your swap partition), find the major and minor numbers of your swap partition, and echo them into /sys/power/resume. For example, if your swap were on /dev/mapper/VolGroup00-LogVol01 which showed

	  brw-rw----  1 root disk 253, 1 Oct  2 03:31 /dev/mapper/VolGroup00-LogVol01
	
then you would echo 253:1 > /sys/power/resume. All of this must be done before any filesystems are mounted. If you wait until afterwards, you are almost guaranteed to have data corruption. It should also have a fallback present in case the resume fails (i.e. the next line after the echo into /sys/power/resume should handle resume failure). [FIXME provide something here that's more useful!]

Once you've got your initrd in place, make sure you edit your grub.conf or other boot configuration file to use the new initrd image file: add a line initrd /initrd-2.6.14-rc3.img (or whatever your kernel name is) to the stanza for booting your new kernel. Example:

	  title Testing (2.6.14-rc3)
          root (hd0,2)
          kernel /vmlinuz-2.6.14-rc3 ro root=/dev/VolGroup00/LogVol00 rhgb quiet
          initrd /initrd-2.6.14-rc3.img
	

To suspend, issue the following command, just as in the discussion above for non-initrd-based suspend: echo shutdown > /sys/power/disk; echo disk > /sys/power/state and observe the same caveats; no hardware changes, don't touch any partition that was mounted when you suspended, don't touch the swap partition.

When you press the power button to resume, the init or linuxrc script in your initrd will start up LVM for you, check for the suspend image on your swap partition, and resume from it. For those who want to know more than they should, the resume works by writing the device name as major:minor device numbers into /sys/power/resume, which causes the kernel to try to resume from the swap on that device. (It bypasses the normal kernel resume path which would use the swap partition name -- something like /dev/mapper/VolGroup00-LogVol01 -- to try to find an underlying physical partition and would fail to find it and fail to resume.) This leads to one last caveat: never write into /sys/power/resume yourself, or you will cause the kernel to try to resume from whatever device you specify, right then and there. That is a sure recipe for disaster!

Using Nvidia drivers with swsusp1 is easy. This document describes the procedure for driver release 7676. Unpack the driver, edit nv.c to change this stanza:

          case PM_SUSPEND_MEM:
            nv_printf(NV_DBG_ERRORS, "NVRM: ACPI: received suspend event\n");
            status = rm_power_management(nv, 0, NV_PM_ACPI_STANDBY);
            break;
	
to read

          case PM_SUSPEND_MEM:
          case PM_SUSPEND_STANDBY:  /* HACK */
            nv_printf(NV_DBG_ERRORS, "NVRM: ACPI: received suspend event\n");
            status = rm_power_management(nv, 0, NV_PM_ACPI_STANDBY);
            break;
	
Rebuild your module and you're ready to go. If you are using the intel_agp module, you may need to use the
Option "NvAgp" "0"
line in the "Device" section of your X configuration file; other than that, no special tweaks should be needed. In some cases, your X display may come back fine but switching to other consoles may give you garbage; I find this to be true on my hardware.

[FIXME put info about ATI drivers here, as needed.]


11.1.3. Swsusp1 Resume failed; now what?

If resume fails after a successful suspend, you have a suspend image written to your swap and you'll have to deal with it.

Add the boot parameter "noresume" to your kernel boot arguments, boot up, and this will cause the kernel to boot normally. If you have the modified swapon, then your swap partition will automatically be set be usable for swap again. If you don't, you'll need to make the partition available for use as swap; do this by mkswap /dev/where-your-swap-is and then swapon -a. Now you are back to normal.


11.1.4. How do I use Suspend to disk 2?

Note: the official name of this code is "Software Suspend 2". In this document, it is usually referred to as swsusp2, even though that's not the preferred name. With three different suspend to disks floating around, it helps me to keep them all straight.

Since Suspend to disk 2 has not been merged into the kernel, you'll have to download the patchset from http://www.suspend2.net/. Version 2.2-rc8 has been released for 2.6.14-rc3 and it applies cleanly. This document only describes working with this version of the patchset. To apply the patch, unpack it, cd into the root of your kernel source tree, and run /path/to/patch-unpacked/apply /path/to/patch-unpacked (the name of the script is apply, and you must tell it where the unpacked patch tree is).

You must also download the hibernate script which goes with it, from the same place. Make sure the hibernate script version goes with the kernel patches. Both rpms and tarballs are available. Assuming you retrieved the hibernate tarball, unpack it, change into the directory where you unpacked it, be root and then run ./install.sh. This puts the scripts and config file in appropriate places. You may want to check /etc/hibernate/hibernate.conf, and the list of modules that hibernate will attempt to unload before suspending, in /etc/hibernate/blacklisted-modules. The defaults are usually ok to test with.

You can either use a swap partition or a file for saving your suspend image. Using a file will be covered in a later version of this document. [FIXME] Make sure you have a swap partition that is at least twice as big as your memory. If your swap is on an LVM partition, read the later part of this section; if it's on raid, there is support also [FIXME].

Back up your data before your first test. No joke! If you happen to have an unsupported driver, bad things can happen.

Now, build your kernel with CONFIG_SUSPEND2=y, CONFIG_SUSPEND2_SWAPWRITER=y, CONFIG_SUSPEND2_CRYPTO=y, CONFIG_SUSPEND2_USERSPACE_UI=y, and CONFIG_SUSPEND2_DEFAULT_RESUME2="". You should specify your resume partition by passing an argument at boot time. Of course, to avoid typos, edit your boot configuration. For Grub users, this means appending the argument "resume2=swap:/dev/something" to your kernel boot line, where "/dev/something" should be replaced with the full name of your swap partition.

If you want to use compression, you should build LZF capability into the kernel, by setting CONFIG_CRYPTO=y and CONFIG_CRYPTO_LZF=y. You can make them into modules but then you must use an initrd image to supply these modules at boot time.

Boot into the new kernel. If you are watching closely, or if you check /var/log/messages, you'll see that the kernel attempts to resume from your swap partition even though there's nothing to resume from (yet). This is normal behavior; your kernel will do this every time. If you see this message: Can't translate "/dev/..." into a device id yet., it means that your swap is not on a physical partition or that you have underlying modules that need to be loaded before the partition can be found. Check that IDE and/or SCSI support is built in directly to the kernel, and try again until this message goes away.

For the first test, you might want to be root and init 3 so that X isn't running. It's also a good idea to unload usb modules, PCMCIA modules, and network/wireless modules.

Now give the following command: /usr/local/sbin/hibernate You will see all devices suspend and then resume again briefly; at this point the swap image will get written and you'll see a progress count. After the image is written, devices will be suspended again and then your system should power off. It's really fast, much faster (in my experience) than swsusp1.

If you have mice or removable devices or other hardware attached to your system, LEAVE THEM ALL AS IS. Don't change the hardware configuration at all; resume expects to resume to a system that is identical to the one it suspended to. Forbidden hardware configuration changes include plugging the the laptop when it was unplugged!

Press the power button briefly, and you will go through the normal boot sequence. Choose the same kernel from the boot menu, with exactly the same kernel arguments you gave before; if you change this, you could lose all of your data.

Once you boot, the system should resume from the image it wrote out earlier, and you'll be returned to the exact state you were in before suspension.

One thing that you may do, without disturbing the resume process at all, is to boot into a different OS, as long as you don't touch the swap partition or the other partitions that were mounted when you did the suspend. You cannot mount them from somewhere else, even if you don't touch anything after the mount. So for example, you could boot into your 64-bit version of Linux on some other disk, do work there, then reboot into the kernel from which you suspended, using the same kernel arguments as for the suspend, and you'll be back where you were at the point of suspension. Don't forget that your hardware configuration must not have changed!

Many other useful entries for swsusp2 are available under /proc/suspend2/. Warning: please note that this location is only valid for swsusp2 versions 2.2-rc8 and later! For earlier versions, you must look in the directory /proc/software_suspend/ instead.

On a system where your swap partition is an LVM partition, you must take a different approach. You must use initrd/initramfs.

Build your kernel with the same configuration options as before.

Now you must get several supporting utilities or patches to them. [FIXME other distros...]

For RedHat/Fedora, you need mkinitrd version 4.2.22-1 or later; utils-linux 2.13-0.3.pre2 or later (for updated swapon); and e2fsprogs 1.38-1 or later. You can either build these from source or get the binary rpms and install them. At this writing, these updates are only available from the rawhide (unstable) release tree, and installing the binary rpms requires installation of glibc*2.3.90-12 or later.

If you are using RH/Fedora, you can use mkinitrd to create an initrd that will support lvm and resume from your swap partition, with some hacking. Change the line
echo "resume $swsuspdev" >> $RCFILE
to
echo "echo > /proc/suspend2/do_resume" >> $RCFILE
. Warning: please note that this location is only valid for swsusp2 versions 2.2-rc8 and later! For earlier versions, you must use the file /proc/software_suspend/do_resume instead. Then you can run mkinitrd --allow-missing -f /boot/initrd-2.6.14-rc3.img 2.6.14-rc3, substituting the actual name of your kernel for 2.6.14-rc3, such as 2.6.13-1.1588_FC5 or whatever uname -r shows you. Mkinitrd will look for the first enabled swap partition and write the commands to make it available and resume from it into the init file in the new initrd.

If you are using another distribution which includes mkinitrd, you should check to see whether they have an updated version which supports lvm and resume from swap on a logical volume. You must use the new mkinitrd to build an initrd image that will be used when you suspend/resume.

It doesn't matter whether your distribution supports the old initrd format or the new cpio format (initramfs); in either case you make the same changes, but for the old format you look at the file linuxrc in the image, and for the new format you look at the file init in the image, to add commands that do the resume.

If you don't want to use your distribution's mkinitrd or your distribution doesn't provide one, then you can build one yourself. At a minimum, it should have a statically linked version of /bin/lvm. Your init or linuxrc script should create /dev/mapper/control, run lvm vgscan --ignorelockingfailure, run lvm vgchange -ay --ignorelockingfailure VolGroup00 (you should include the volume groups that contain your rootfs and your swap partition), and echo *gt; /proc/suspend2/do_resume. All of this must be done before any filesystems are mounted. If you wait until afterwards, you are almost guaranteed to have data corruption. It should also have a fallback present in case the resume fails (i.e. the next line after the echo into /proc/suspend2/do_resume should handle resume failure). [FIXME provide something here that's more useful!]

Once you've got your initrd in place, make sure you edit your grub.conf or other boot configuration file to use the new initrd image file: add a line initrd /initrd-2.6.14-rc3.img (or whatever your kernel name is) to the stanza for booting your new kernel. Example:

	  title Testing (2.6.14-rc3)
          root (hd0,2)
          kernel /vmlinuz-2.6.14-rc3 ro root=/dev/VolGroup00/LogVol00 rhgb quiet resume2=swap:/dev/mapper/VolGroup00-LogVol01
          initrd /initrd-2.6.14-rc3.img
	

To suspend, issue the following command, just as in the discussion above for non-initrd/initramfs-based suspend: /usr/local/sbin/hibernate and observe the same caveats; no hardware changes, don't touch any partition that was mounted when you suspended, don't touch the swap partition.

When you press the power button to resume, the init or linuxrc script in your initrd will start up LVM for you, check for the suspend image on your swap partition, and resume from it. And if you haven't realized it yet, never write into /proc/suspend2/do_resume yourself, or you will cause the kernel to try to resume from whatever device you specify, right then and there. That is a sure recipe for disaster!

Using Nvidia drivers with swsusp2 may take a little work. You'll have to rebuild your nvidia module as described above for swsusp1, and install it. Change any settings in your xorg.conf file as well, as described above.

Then try the suspend. If it doesn't work, what may happen is that you see some disk activity, the screen goes blank, there's more disk activity, and then the machine stays on. If this happens to you, see if Ctl-Alt-Delete will let you reboot your machine. If it does, then check your logs to see if there is a complaint like "Pageset1 has grown by 381 pages. Only 100 growth is allowed for!". If there is, you can (probably) change one line and get swsusp2 to run.

If in your log you instead see a lot of lines like

	  scheduling while atomic: hibernate/0x00000002/3313
	  [<c01037d7>] dump_stack+0x17/0x20
	  [<c036fdf7>] schedule+0x557/0x620
	  [<c037075e>] io_schedule+0xe/0x20
	  [<c0141a59>] do_bio_wait+0x19/0x30
	  [<c0141bea>] wait_on_one_page+0x1a/0x30
	  [<c0142389>] suspend_do_io+0x39/0x40
	  [<c01423bf>] suspend_bdev_page_io+0x2f/0x40
	  [<c0143e3d>] swapwriter_invalidate_image+0x5d/0x110
	  [<c013cc80>] suspend2_main+0xe0/0x1d0
	  [<c013f1fa>] suspend2_write_proc+0xba/0x270
	  [<c01a63e4>] proc_file_write+0x34/0x50
	  [<c016bc61>] vfs_write+0xb1/0x170
	  [<c016bdcd>] sys_write+0x3d/0x70
	  [<c01031d5>] syscall_call+0x7/0xb
	
there may be so many of them that they overflow the message buffer and you don't see all the steps for suspend/resume logged. To turn these off for the moment, you'll need to edit kernel/sched.c, and in the schedule() function, edit this bit:

	  if (likely(!current->exit_state)) {
              if (unlikely(in_atomic())) {
                  printk(KERN_ERR "scheduling while atomic: "
                                  "%s/0x%08x/%d\n",
                                  current->comm, preempt_count(), current->pid); 
                                  dump_stack(); 
             }
        }
	
to comment out the
printk()
and the
dump_stack()
lines. Then run the suspend again; you should be able to see the real suspend/resume errors and check what's wrong. When you are done, uncomment these lines and rebuild your kernel again, because these catch other errors than those just in swsusp2.

In your linux kernel source tree with the suspend2 patches applied, edit kernel/power/prepare_image.h: and change the line
#define EXTRA_PD1_PAGES_ALLOWANCE 100
to read
prepare_image.h:#define EXTRA_PD1_PAGES_ALLOWANCE 500
. This assumes that the pageset1 growth is < 500 pages. If it's much more than that, this may be a sign of some other problem.

In some cases, your X display may come back fine but switching to other consoles may give you garbage; I find this to be true on my hardware.

[FIXME put info about ATI drivers here, as needed.]

Note: If you are using Fedora Core 3 or 4, Matthias Hensler maintains kernel rpms and special versions of mkinitrd at http://mhensler.de/swsusp/ which you can use. Rpms for the hibernate script are also available for download there.


11.1.5. Swsusp2 Resume failed; now what?

If resume fails after a successful suspend, you have a suspend image written to your swap and you'll have to deal with it.

Add the boot parameter "noresume2" to your kernel boot arguments, boot up, and this will cause the kernel to boot normally. If you have the modified swapon, then your swap partition will automatically be set be usable for swap again. If you don't, you'll need to make the partition available for use as swap; do this by mkswap /dev/where-your-swap-is and then swapon -a. Now you are back to normal.


11.1.6. Suspend to disk 3

Note: there is no official name for this version of suspend to disk. It's referred to as swsusp3 in this document because that name has been used in a couple of postings (and rejected, too :-)) And it is the third set of code in current development.

Swsusp3 is a set of very preliminary patches that Pavel Machek is cooking up. Don't use these unless you like being on the very bleeding edge and don't mind restoring all of your data. These patches were first introduced on the Linux kernel mailing list and linux-pm in mid-September; see http://lkml.org/lkml/2005/9/14/377 and http://lists.osdl.org/pipermail/linux-pm/2005-September/001358.html for the patches and discussions on both lists.

So you really really shouldn't do this at home, kids.

But if you just have to try it anyways, first, back up all of your data. Really. Not like you pretended to back it up for swsusp1 or swsusp2 and you went ahead and built the kernel and crossed your fingers and hoped. Go Do It Now.

Make sure you have a swap partition, not a swap file, that it's on a separate physical partition, and that it's at least as big as your memory. If your swap partition is on an LVM partition, read the later part of this section; if it's on raid, you're on your own.

The patches on the linux kernel mailing list are a bit older. I have a patch generated from Pavel Machek's git tree which almost applies cleanly to 2.6.14-rc4, and the one piece that doesn't, doesn't matter right now (it's a comment and one line of code).

You can get the patch from http://www.columbia.edu/~ariel/acpi/swsusp3-2.6.14-rc4.txt for the moment. Or you can pull his tree for yourself and generate your own bleepin' patch.

Now, build your kernel with CONFIG_SOFTWARE_SUSPEND=y. Build your kernel with CONFIG_SOFTWARE_SUSPEND=y. For CONFIG_PM_STD_PARTITION, set the value to "". DO NOT pass any resume= argument to the kernel at boot time or in your grub.conf. At suspend time, this will cause the kernel to look for the first swap partition it can see and use it to write the memory image.

Boot into the new kernel. If you are watching closely, or if you check /var/log/messages, you'll see that the kernel attempts to resume from your swap partition even though there's nothing to resume from (yet). This is normal behavior; your kernel will do this every time. Swsusp3 will complain if it can't find your swap partition; if so, check that your swap is on a physical partition and that any underlying modules that need to be loaded before the partition can be found. Check that IDE and/or SCSI support is built in directly to the kernel, and try again until the message goes away.

You have a little bit of prep to do first before using this suspend. Go to the root of your linux kernel tree and cd into usr/. Edit the file swsusp.c, changing the lines

	  #include "/data/l/linux-sw3/include/linux/suspend.h" */
	  #include "/data/l/linux-sw3/include/linux/reboot.h" */
	
to

	  #include "linux/suspend.h"
	  #include "linux/reboot.h"
	
Build the program swsusp.c by running gcc -g -Wall usr/swsusp.c -o usr/swsusp-bin -static -I. You need this to be statically built because it's going to go into your initrd image w