An overview of the concepts and the related functions in the Linux kernel
Patrick Mochel <mochel@transmeta.com>
+(and others)
---------------------------------------------------------------------------
the higher the number, the longer the latency is for the device to return to
an operational state (D0).
+There are actually two D3 states. When someone talks about D3, they usually
+mean D3hot, which corresponds to an ACPI D2 state (power is reduced, the
+device may lose some context). But they may also mean D3cold, which is an
+ACPI D3 state (power is fully off, all state was discarded); or both.
+
Bus power management is not covered in this version of this document.
-Note that all PCI devices support D0 and D3 by default, regardless of whether or
-not they implement any of the PCI PM spec.
+Note that all PCI devices support D0 and D3cold by default, regardless of
+whether or not they implement any of the PCI PM spec.
The possible state transitions that a device can undergo are:
events, which is implicit if it doesn't even support it in the first
place).
- Note that the PMC Register in the device's PM Capabilties has a bitmask
+ Note that the PMC Register in the device's PM Capabilities has a bitmask
of the states it supports generating PME# from. D3hot is bit 3 and
D3cold is bit 4. So, while a value of 4 as the state may not seem
semantically correct, it is.
These functions are intended for use by individual drivers, and are defined in
struct pci_driver:
- int (*save_state) (struct pci_dev *dev, u32 state);
- int (*suspend) (struct pci_dev *dev, u32 state);
+ int (*suspend) (struct pci_dev *dev, pm_message_t state);
int (*resume) (struct pci_dev *dev);
- int (*enable_wake) (struct pci_dev *dev, u32 state, int enable);
-
-
-save_state
-----------
-
-Usage:
-
-if (dev->driver && dev->driver->save_state)
- dev->driver->save_state(dev,state);
-
-The driver should use this callback to save device state. It should take into
-account the current state of the device and the requested state in order to
-avoid any unnecessary operations.
-
-For example, a video card that supports all 4 states (D0-D3), all controller
-context is preserved when entering D1, but the screen is placed into a low power
-state (blanked).
-
-The driver can also interpret this function as a notification that it may be
-entering a sleep state in the near future. If it knows that the device cannot
-enter the requested state, either because of lack of support for it, or because
-the device is middle of some critical operation, then it should fail.
-
-This function should not be used to set any state in the device or the driver
-because the device may not actually enter the sleep state (e.g. another driver
-later causes causes a global state transition to fail).
-
-Note that in intermediate low power states, a device's I/O and memory spaces may
-be disabled and may not be available in subsequent transitions to lower power
-states.
+ int (*enable_wake) (struct pci_dev *dev, pci_power_t state, int enable);
suspend
dev->driver->suspend(dev,state);
A driver uses this function to actually transition the device into a low power
-state. This may include disabling I/O, memory and bus-mastering, as well as
-physically transitioning the device to a lower power state.
+state. This should include disabling I/O, IRQs, and bus-mastering, as well as
+physically transitioning the device to a lower power state; it may also include
+calls to pci_enable_wake().
Bus mastering may be disabled by doing:
pci_disable_device(dev);
For devices that support the PCI PM Spec, this may be used to set the device's
-power state:
+power state to match the suspend() parameter:
pci_set_power_state(dev,state);
obviate the need for some operations.
The driver should update the current_state field in its pci_dev structure in
-this function.
+this function, except for PM-capable devices when pci_set_power_state is used.
resume
------
transition the device to the D0 state.
The driver is responsible for reenabling any features of the device that had
-been disabled during previous suspend calls and restoring all state that was
-saved in previous save_state calls.
+been disabled during previous suspend calls, such as IRQs and bus mastering,
+as well as calling pci_restore_state().
+
+If the device is currently in D3, it may need to be reinitialized in resume().
-If the device is currently in D3, it must be completely reinitialized, as it
-must be assumed that the device has lost all of its context (even that of its
-PCI config space). For almost all current drivers, this means that the
-initialization code that the driver does at boot must be separated out and
-called again from the resume callback. Note that some values for the device may
-not have to be probed for this time around if they are saved before entering the
-low power state.
+ * Some types of devices, like bus controllers, will preserve context in D3hot
+ (using Vcc power). Their drivers will often want to avoid re-initializing
+ them after re-entering D0 (perhaps to avoid resetting downstream devices).
+
+ * Other kinds of devices in D3hot will discard device context as part of a
+ soft reset when re-entering the D0 state.
+
+ * Devices resuming from D3cold always go through a power-on reset. Some
+ device context can also be preserved using Vaux power.
+
+ * Some systems hide D3cold resume paths from drivers. For example, on PCs
+ the resume path for suspend-to-disk often runs BIOS powerup code, which
+ will sometimes re-initialize the device.
+
+To handle resets during D3 to D0 transitions, it may be convenient to share
+device initialization code between probe() and resume(). Device parameters
+can also be saved before the driver suspends into D3, avoiding re-probe.
If the device supports the PCI PM Spec, it can use this to physically transition
the device to D0:
ensure correct (and speedy) operation.
The driver should update the current_state field in its pci_dev structure in
-this function.
+this function, except for PM-capable devices when pci_set_power_state is used.
enable_wake
some non-standard way of generating a wake event on sleep.)
Bits 15:11 of the PMC (Power Mgmt Capabilities) Register in a device's
-PM Capabilties describe what power states the device supports generating a
+PM Capabilities describe what power states the device supports generating a
wake event from:
+------------------+
pci_enable_wake (one for both D3hot and D3cold).
+A reference implementation
+-------------------------
+.suspend()
+{
+ /* driver specific operations */
+
+ /* Disable IRQ */
+ free_irq();
+ /* If using MSI */
+ pci_disable_msi();
+
+ pci_save_state();
+ pci_enable_wake();
+ /* Disable IO/bus master/irq router */
+ pci_disable_device();
+ pci_set_power_state(pci_choose_state());
+}
+
+.resume()
+{
+ pci_set_power_state(PCI_D0);
+ pci_restore_state();
+ /* device's irq possibly is changed, driver should take care */
+ pci_enable_device();
+ pci_set_master();
+
+ /* if using MSI, device's vector possibly is changed */
+ pci_enable_msi();
+
+ request_irq();
+ /* driver specific operations; */
+}
+
+This is a typical implementation. Drivers can slightly change the order
+of the operations in the implementation, ignore some operations or add
+more driver specific operations in it, but drivers should do something like
+this on the whole.
+
5. Resources
~~~~~~~~~~~~
PCI Local Bus Specification
PCI Bus Power Management Interface Specification
- http://pcisig.org
+ http://www.pcisig.com