[Previous] [Contents] [Next]

Caution: This version of this document is no longer maintained. For the latest documentation, see http://www.qnx.com/developers/docs.

Implementing a System Power Management Policy

This chapter contains the following topics:

Overview

This chapter gives you the resources to implement a system-wide power management policy. As already mentioned in the Power Management Architecture chapter, QNX Neutrino's power manager framework has two important parts: the server and the client. This chapter describes the server for building the power manager, including a rich set of server library routines (or APIs) that help you build the power manager itself.

The server provides the following sets of services for building a product-specific power manager:

The server library provides a number of APIs broken down into the following functional groups:

Please refer to the API Reference chapter for more information.

Power manager nodes

Power manager nodes represent the power managed entities in a system. A node is a (power manager) library specific concept/data structure that contains the following:


Note: Not all nodes have a driver process responsible for managing the power mode. These nodes are not power managed.

Nodes are created in a number of ways:


Note: The organization and meaning of the namespace is entirely defined by the product-specific power manager policy.

This implies that some sort of cooperation is needed between device drivers and the power manager in order to agree on the naming conventions that allow drivers to determine and attach to the relevant nodes.


Power manager namespace

The power manager implements a hierarchical namespace that represents the power managed entities. The namespace is built using two kinds of nodes:

directory nodes
The nodes represent power managed subsystems that contain a number of peripherals, e.g. buses. In this case, a bus driver is attached to the node to manage the bus power mode. The nodes also provide a naming context for the peripherals.

The directory nodes are also used for configuration or organizational purposes. In this case, there is no power management for the node itself, and it simply provides a naming context for other nodes.

leaf nodes
These nodes represent individual power managed devices. In this case, a driver is attached to the node to manage the device power mode.

The leaf nodes are also used for control purposes without having an associated driver. In this case, power manager properties are associated with the node. Manipulation of these properties by clients can be used to control aspects of the power manager behavior or policy.

Power mode management

The server provides the basic support for triggering and monitoring changes to the power mode on individual nodes.

The product-specific policy can change the power mode of a node. This results in a request being made to the driver responsible for the node's power mode. This request is asynchronous, and the power mode state is updated when the driver completes the request and confirms its new power mode. The library delivers notification of changes to the power mode state to registered clients.

The product-specific policy is informed when the driver changes the power mode. This is in response to a request initiated by the power manager or from the driver itself independent of the power manager policy.


Note: The library implements control of individual node only; it doesn't manage the sequencing of power mode changes for groups of nodes.

This is the responsibility of the product-specific policy code. For example, when powering down a subsystem, the policy code is responsible for powering down individual devices within the subsystem before powering down the subsystem itself.


Product-specific policies

The server provides support for product-specific policy implementation in order to control many aspects of the life cycle for a power manager node. This is achieved by a set of policy functions that are invoked when:

Implementing a power manager

The power manager you implement in accord with a product-specific must:

Once the server interface is started, the power manager becomes event driven, and the policy receives control via the policy-specific functions. These policy functions use some policy specific data to manage the overall system power mode state.

It is possible to use only default policy functions to provide a very basic power manager. This power manager simply acts as a conduit between device drivers and other clients using power manager interfaces, such that:

This simple policy doesn't handle power dependencies between devices. Control and management of these devices must be performed by client applications using the power manager interface.

To create a functional power manager using the default policy, you may use the following code:

#include <sys/pmm.h>
#include <sys/procmgr.h>

int
main(int argc, char *argv[])
{
   // initialize and start the power manager interface
   if (pmm_init(0) != EOK) {
   exit(1);
   }
   pmm_start(0, 0);

   // become a daemon
   procmgr_daemon(EXIT_SUCCESS, 0);
   pthread_detach(pthread_self());
   pthread_exit(0);
   return 0;
}

The server library

Power manager server

The server library provides the following interfaces to handle power manager clients:

Use this function: To:
pmm_init() Initialize power manager resource manager interface
pmm_start() Start a thread pool to handle client requests

The resource manger interface implements a subset of the standard POSIX iofunc layer calls. It also implements power manager specific operations via the custom message structures described in the client routines in the API Reference chapter:

io_open
Used by pm_attach() and pmd_attach(). In addition, the standard file creation commands and library calls allow external agents to create leaf power manager nodes.
io_mknod
Allows external agents to use standard directory creation commands and library calls to create directory power manager nodes.
io_unlink
Allows external agents to use standard file or directory removal commands and library calls to unlink power manager nodes.
io_msg
Implements the power manager client messages.
io_read
Allows external agents to use standard directory reading commands and library calls to list directory entries for directory nodes.

The iofunc_read_default() function is used for nondirectory nodes.

io_close_ocb
Implements the file close and connection detach handling.

You can manage the namespace using any combination of the following:

Access control and ownership of power manager nodes follow the standard filesystem semantics:

Power managed objects

Each power managed object is represented by a _pmm_node_t structure. This is an extension of the iofunc_attr_t that adds power manager-specific data, as follows:

This structure is opaque to the product-specific policy code, and can be manipulated only via:

The public interface for manipulating power manager nodes consists of the following functions:

Use this function: To:
pmm_node_create() Create a new node
pmm_node_lookup() Lookup a node by name
pmm_node_unlink() Unlink a node
pmm_mode_get() Get the current power mode of a node
pmm_mode_list() Get the list of modes supported by a node
pmm_mode_change() Change the power mode of a node
pmm_mode_wait() Wait until a mode change has completed
pmm_property_add() Add a new property to a node
pmm_property_set() Set the value of a property
pmm_property_get() Get the current value of a property
pmm_property_list() List all properties associated with a node

Support for product-specific policies

In order to receive control during client requests on a particular node, the server library provides hooks for:

This support is provided by the following function and structure:

pmm_policy_funcs()
Get a pointer to the policy function table
pmm_policy_funcs_t
Contains a table of policy specific callbacks

Callbacks

Callbacks are available as follows:

Call this callback: When a:
create() New node is created
destroy() Node is destroyed
unlink() Node to be unlinked from the namespace
attach() Client attaches to a power manager node
detach() Client detaches from power manager node
mode_init() Driver attaches to a power manager node and supplies the initial power modes
mode_request() Request is made to change the power mode for a node
mode_confirm() Driver confirms a mode change has been completed
property_add() Client adds a new property to a node
property_set() Client modifies a property value

State machine datatype and APIs

The following table lists the state machine datatype and APIs:

Datatype and APIs Purpose
pmm_state_t Represent the state
pmm_state_init() Create a state machine
pmm_state_machine() Execute the state machine from the calling thread
pmm_state_trigger() Trigger the state machine thread to re-evaluate the current state
pmm_state_check() Evaluate the current state
pmm_state_change() Change state

State machine operations

This section describes how to construct state machines that are used to describe and manage the system's power mode state.

Each power mode state is represented by a pmm_state_t structure that specifies:

The pmm_state_init() creates a new state machine using an array of pmm_state_t structures that describe the set of allowable states.

This is used to create multiple state machines that operate independently, or interact together to implement nested state machines.

The state machine APIs support the following modes of operation:

Single-threaded state machines

The basic steps involved are:

  1. Define the system states and data associated with the state machine:
    pmm_state_t my_states[NSTATES] = {
       :
    };
    struct my_data *my_data;
  2. Initialize the state machine:
    hdl = pmm_state_init(NSTATES, my_states, my_data, MY_INITIAL_STATE);
  3. Execute the state machine:
    if (pmm_state_machine(hdl) != EOK) {
       error handling...
    }

    Because this call never returns, it must be the last initialization action that this thread performs.

Once the state machine thread is running, other threads can trigger state changes by calling pmm_state_trigger(hdl). This will cause the state machine thread to re-evaluate the current state and perform a state transition to a new state, if necessary.

Multi-threaded state machines

The basic steps involved are:

  1. Define the system states and data associated with the state machine:
    pmm_state_t my_states[NSTATES] = {
       :
    };
    struct my_data *my_data;
  2. Initialize the state machine:
    hdl = pmm_state_init(NSTATES, my_states, my_data, MY_INITIAL_STATE);

Once the state machine is initialized, any thread in the power manager can re-evaluate and change the system state as follows:

pmm_state_check(hdl, &cur_state, &new_state);
if (new_state != cur_state)
   pmm_state_change(hdl, new_state);

Alternatively, a thread may unconditionally change the state using (?)

The implementation ensures mutual exclusion between these two functions so that:

Nested state machines

You can build nested state machines where sub-state machines can affect state transitions on higher-level state machines:

For example, the power manager could implement separate state machines for each subsystem that implements a set of services, and the state of these individual subsystems can be used to control the system's power mode state.

An example of power manager


[Previous] [Contents] [Next]