Writing Device Drivers

Chapter 9 Power Management

Power management provides the ability to control and manage the electrical power usage of a computer system or device. Power management enables systems to conserve energy by using less power when idle and by shutting down completely when not in use. For example, desktop computer systems can use a significant amount of power, and often (particularly at night) are left idle. Power management software can detect that the system is not being used and power it or some of its components down.

This chapter provides information on the following subjects:

Power Management Framework

The Solaris Power Management framework depends on device drivers to implement device-specific power management functionality. The framework is implemented in two parts:

Device Power Management

The framework allows devices to reduce their energy consumption after a specified idle time interval. To perform effective device power management, system software monitors the different devices and determines when they are not in use. Since only device drivers are able to determine when a device is idle, and only device drivers are able to reduce power consumption of a device, the Power Management framework exports interfaces to enable communication between the system software and the device driver.

The Solaris Power Management framework provides the following:

System Power Management

System power management consists of turning off the entire computer after saving its state so that it can be returned to the same state immediately when it is turned back on.

To shut down an entire system and later return it to the state it was in prior to the shutdown:


SPARC only –

System power management is currently implemented only on some SPARC systems supported by the Solaris 9 operating environment.


The Solaris operating environment System Power Management framework provides the following:

Device Power Management Model

The following sections describe the details of the device power management model. This model includes the following elements:

Power Management Components

A device is power manageable if the power consumption of the device can be reduced when it is idle. Conceptually, a power manageable device consists of a number of power-manageable hardware units called components.

The device driver notifies the system of the existence of device components and the power levels that they support by creating a pm-components(9P) property in its attach(9E) entry point as part of driver initialization.

Most devices that are power manageable implement only a single component. An example of a single-component, power-manageable device is a disk whose spindle motor can be stopped to save power when the disk is idle.

If a device has multiple power-manageable units that are separately controllable, it should implement multiple components.

An example of a two-component, power-manageable device is a frame buffer card with a monitor connected to it. Frame buffer electronics is the first component [component 0]. Its power consumption can be reduced when not in use. The monitor is the second component [component 1], which can also enter a lower power mode when not in use. The combination of frame buffer electronics and monitor is considered by the system as one device with two components.

Multiple Power Management Components

To the power management framework, all components are considered equal and completely independent of each other. If this is not true for a particular device, the device driver must ensure that undesirable state combinations do not occur. For example, with a frame buffer/monitor card with a monitor attached to it, for each possible power state of the monitor (On, Standby, Suspend, Off) there are states of the frame buffer electronics (D0, D1, D2, D3) that are not allowed if the device is to work properly. If the monitor is On, then the frame buffer must be at D0 (full on), so if the frame buffer driver gets a request to power up the monitor to On while the frame buffer is D3, it must ask the system to bring the frame buffer back up (by calling pm_raise_power(9F)) before setting the monitor On. If the frame buffer driver gets a request from the system to lower the power of the frame buffer while the monitor is On, it must fail that request.

Power Management States

Each component of a device may be in one of two states: busy or idle. The device driver notifies the framework of changes in the device state by calling pm_busy_component(9F) and pm_idle_component(9F). When components are initially created, they are considered idle.

Power Levels

From the pm-components property exported by the device, the Device Power Management framework knows what power levels the device supports. Power level values must be positive integers. The interpretation of power levels is determined by the device driver writer, but they must be listed in monotonically increasing order in the pm-components property, and a power level of 0 is interpreted by the framework to mean off. When the framework must power up a device because of a dependency, it will bring each component to its highest power level.

Example 9–1 is an example pm-components entry from the .conf file of a driver that implements a single power-managed component consisting of a disk spindle motor. The disk spindle motor is component 0 and it supports 2 power levels, which represent stopped and spinning full speed.


Example 9–1 Sample pm-component Entry

pm-components="NAME=Spindle Motor", "0=Stopped", "1=Full Speed";

Example 9–2 shows an example of how Example 9–1 could be implemented in the attach() routine of the driver.


Example 9–2 attach(9E) Routine With pm-components Property

static char *pmcomps[] = {
        "NAME=Spindle Motor",
        "0=Stopped",
        "1=Full Speed"
};

...

xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
...
        if (ddi_prop_update_string_array(DDI_DEV_T_NONE, dip,
            "pm-components", &pmcomp[0],
            sizeof (pmcomps) / sizeof (char *)) != DDI_PROP_SUCCESS)
                goto failed;
...

Example 9–3 shows a frame buffer that implements two components. Component 0 is the frame buffer electronics that support four different power levels. Component 1 represents the state of power management of the attached monitor.


Example 9–3 Multiple Component pm-components Entry

pm-components="NAME=Frame Buffer", "0=Off", "1=Suspend", \
        "2=Standby", "3=On",
        "NAME=Monitor", "0=Off", "1=Suspend", "2=Standby", "3=On";

When a device driver is first attached, the framework does not know the power level of the device. A power transition may occur when:

Once a power transition has occurred or the driver has informed the framework of the power level, the framework tracks the current power level of each component of the device. The driver can inform the framework of a power level change by calling pm_power_has_changed(9F).

The system calculates a default threshold for each possible transition from one power level to the next lower level, based on the system idleness threshold. These default thresholds can be overridden using dtpower(1M) or power.conf(4). Another default threshold based on the system idleness threshold is used when the component power level is unknown.

Power Management Dependencies

Some devices should be powered down only when other devices are also powered down. For example, if removable-media devices such as CD-ROM drives or Zip drives are allowed to power down by themselves, functionality associated with their current state, such as the ability to eject a CD or to respond when a new Zip disk is inserted, may be lost.

One way to prevent a device from powering down independently is to make the device dependent on another device that is likely to remain powered on while its functionality is required. Typically, the device is made dependent upon a frame buffer, because a monitor is generally on whenever a user is utilizing a system.

The power.conf(4) file specifies the dependencies among devices. (A parent node in the device tree implicitly depends upon its children. This dependency is handled automatically by the power management framework.) You can specify a particular dependency with a power.conf(4) entry of this form:


device-dependency dependent_phys_path phys_path

where dependent_phys_path is the device that is kept powered up (such as the CD-ROM drive) and phys_path is the device whose power state it depends on (such as the frame buffer).

Because it would be burdensome to add an entry to power.conf for every new device plugged into the system, another syntax enables you to indicate dependency in a more general fashion:


device-dependency-property property phys_path

Such an entry mandates that any device that exports the property property will be dependent upon the device named by phys_path. Because this dependency applies especially to removable-media devices, /etc/power.conf includes the following line by default:


device_dependent-property  removable-media  /dev/fb

to signal that any device exporting the removable-media property will not be powered down unless the console frame buffer is also powered down.

For more information, see the power.conf(4) and removable-media(9P) man pages.

Automatic Power Management for Devices

If automatic power management is enabled by dtpower(1M) or power.conf(4), then all devices with a pm-components(9P) property automatically will be power managed. After each component has been idle for a default period, it will be automatically brought to its next lowest power level. The default period is calculated by the power management framework to set the entire device to its lowest power state within the system idleness threshold.


Note –

By default automatic power management is enabled on all SPARC desktop systems first shipped after July 1, 1999. This feature is disabled by default for all other systems. To determine if automatic power management is enabled on your machine, refer to the power.conf(4) man page for instructions.


dtpower(1M) or power.conf(4) may be used to override the defaults calculated by the framework.

Device Power Management Interfaces

A device driver that supports a device with power-manageable components must notify the system of the existence of these components and the power levels that they support by creating a pm-components(9P) property. This is typically done from the driver's attach(9E) entry point by calling ddi_prop_update_string_array(9F), but may be done from a driver.conf(4) file instead. See the pm-components(9P) man page for details.

Busy-Idle State Transitions

The driver must keep the framework informed of device state transitions from idle to busy or busy to idle. Where these transitions happen is entirely device-specific. The transitions from idle to busy and from busy to idle depend on the nature of the device and the abstraction represented by the specific component. For example, SCSI disk target drivers typically export a single component, which represents whether the SCSI target disk drive is spun up or not. It is marked busy whenever there is an outstanding request to the drive and idle when the last queued request finishes. Some components are created and never marked busy (components created by pm-components(9P) are created in an idle state).

The pm_busy_component(9F) and pm_idle_component(9F) interfaces notify the power management framework of busy-idle state transitions. The syntax for pm_busy_component(9F) is:

    int pm_busy_component(dev_info_t *dip, int component);

pm_busy_component(9F) marks component as busy. While the component is busy, it will not be powered off. If the component is already powered off, then marking it busy doesn't change its power level. The driver needs to call pm_raise_power(9F) for this purpose. Calls to pm_busy_component(9F) are cumulative and require a corresponding number of calls to pm_idle_component(9F) to idle the component.

The syntax for pm_idle_component(9F) is:

int pm_idle_component(dev_info_t *dip, int component);

pm_idle_component(9F) marks component as idle. An idle component is subject to being powered off. pm_idle_component(9F) must be called once for each call to pm_busy_component(9F) in order to idle the component.

Device Power State Transitions

A device driver can call pm_raise_power(9F) to request that a component be set to at least a given power level. This is necessary before using a component that has been powered off. For example, a SCSI disk target driver's read(9E) or write(9E) routine might need to spin up the disk before completing the read or write, if the disk has already been powered off. pm_raise_power(9F) requests the power management framework to initiate a device power state transition to a higher power level. Normally, reductions in component power levels are initiated by the framework. However, a device driver should call pm_lower_power(9F) when detaching, in order to reduce the power consumption of unused devices as much as possible.

Powering down can pose risks for some devices. For example, some tape drives damage tapes when power is removed; likewise, some disk drives have a limited tolerance for power cycles, since each cycle results in a head landing. Such devices should export the no-involuntary-power-cycles(9P) property to notify the system that all power cycles for the device must be under control of a device driver. This prevents power from being removed from a device while the device driver is detached, unless the device was powered off by a driver's call to pm_lower_power(9F).

pm_raise_power(9F) is called when the driver discovers that a component needed for some operation is at a power level less than is needed for that operation. This interface arranges for the driver to be called to raise the current power level of the component at least to the level specified in the request. All the devices that depend on this device are also brought back to full power by this call.

pm_lower_power(9F) is called when the device is detaching, once access to the device is no longer needed. It should be called for each component to set each component to its lowest power so that the device uses as little power as possible while it is not in use. The syntax for pm_lower_power(9F) is the same as that for pm_raise_power(9F).

pm_power_has_changed(9F) is called to notify the framework when a device has made a power transition on its own, or to inform the framework of the power level of a device, for example, after a suspend-resume operation. The syntax for pm_power_has_changed(9F) is the same as that for pm_raise_power(9F).

power() Entry Point

The power management framework uses the power(9E) entry point.

The syntax for power(9E) is:

    int power(dev_info_t *dip, int component, int level);

The system calls the power(9E) entry point (either directly or as a result of a call to pm_raise_power(9F) or pm_lower_power(9F)) when it determines that a component's current power level needs to be changed. The action taken by this entry point is device driver specific. In the example of the SCSI target disk driver mentioned previously, setting the power level to 0 results in sending a SCSI command to spin down the disk, while setting the power level to the full power level results in sending a SCSI command to spin up the disk.

If a power transition will cause the device to lose state, then the driver must ensure that any necessary state is saved in memory so that it can be restored when it is needed again. If a power transition will require that saved state be restored before the device can be used again, then the driver must restore that state. The framework makes no assumptions about what power transactions cause the loss of or require the restoration of state for automatically power-manage devices. Example 9–4 shows a sample power(9E) routine.


Example 9–4 power(9E) Routine for Single-Component Device

int
xxpower(dev_info_t *dip, int component, int level)
{
        struct xxstate *xsp;
        int instance;

        instance = ddi_get_instance(dip);
        xsp = ddi_get_soft_state(statep, instance);
        /*
         * Make sure the request is valid
         */
        if (!xx_valid_power_level(component, level))
                return (DDI_FAILURE);
        mutex_enter(&xsp->mu);
        /*
         * If the device is busy, don't lower its power level
         */
        if (xsp->xx_busy[component] &&
            xsp->xx_power_level[component] > level) {
                mutex_exit(&xsp->mu);
                return (DDI_FAILURE);
        }

        if (xsp->xx_power_level[component] != level) {
                /*
                 * device- and component-specific setting of power level
                 * goes here
                 */
                ...
                xsp->xx_power_level[component] = level;
        }
        mutex_exit(&xsp->mu);
        return (DDI_SUCCESS);
}

Example 9–5 is a power(9E) routine for a device with two components, where component 0 must be on when component 1 is on.


Example 9–5 power(9E) Routine for Multiple-Component Device

int
xxpower(dev_info_t *dip, int component, int level)
{
        struct xxstate *xsp;
        int instance;

        instance = ddi_get_instance(dip);
        xsp = ddi_get_soft_state(statep, instance);
        /*
         * Make sure the request is valid
         */
        if (!xx_valid_power_level(component, level))
                return (DDI_FAILURE);
        mutex_enter(&xsp->mu);
        /*
         * If the device is busy, don't lower its power level
         */
        if (xsp->xx_busy[component] &&
            xsp->xx_power_level[component] > level) {
                mutex_exit(&xsp->mu);
                return (DDI_FAILURE);
        }

        /*
         * This code implements inter-component dependencies:
         * If we are bringing up component 1 and component 0 
         * is off, we must bring component 0 up first, and if
         * we are asked to shut down component 0 while component
         * 1 is up we must refuse
         */
        if (component == 1 && level > 0 && xsp->xx_power_level[0] == 0) {
                xsp->xx_busy[0]++;
                if (pm_busy_component(dip, 0) != DDI_SUCCESS) {
                        /*
                         * This can only happen if the args to 
                         * pm_busy_component()
                         * are wrong, or pm-components property was not
                         * exported by the driver.
                         */
                        xsp->xx_busy[0]--;
                        mutex_exit(&xsp->mu);
                        cmn_err(CE_WARN, "xxpower pm_busy_component() 
                            failed");
                        return (DDI_FAILURE);
                }
                mutex_exit(&xsp->mu);
                if (pm_raise_power(dip, 0, XX_FULL_POWER_0) != DDI_SUCCESS)
                        return (DDI_FAILURE);
                mutex_enter(&xsp->mu);
        }
        if (component == 0 && level == 0 && xsp->xx_power_level[1] != 0) {
                mutex_exit(&xsp->mu);
                return (DDI_FAILURE);
        }
        if (xsp->xx_power_level[component] != level) {
                /*
                 * device- and component-specific setting of power level
                 * goes here
                 */
                ...
                xsp->xx_power_level[component] = level;
        }
        mutex_exit(&xsp->mu);
        return (DDI_SUCCESS);
}

System Power Management Model

This section describes the details of the System Power Management model. The model includes the following components:

Autoshutdown Threshold

The system may be shut down (powered off) automatically after a configurable period of idleness. This period is known as the autoshutdown threshold. This behavior is enabled by default for SPARC desktop systems first shipped after October 1, 1995 and before July 1, 1999. It may be overridden using dtpower(1M) or power.conf(4).

Busy State

There are several ways to measure the busy state of the system. The currently supported built-in metrics are keyboard characters, mouse activity, tty characters, load average, disk reads, and NFS requests. Any one of these may make the system busy. In addition to the built-in metrics, an interface is defined for running a user-specified process that may indicate that the system is busy.

Hardware State

Devices that export a reg property are considered to have hardware state that must be saved prior to shutting down the system. A device that does not have a reg property is considered to be stateless. However, this consideration can be overridden by the device driver.

A device that has hardware state but no reg property (such as a SCSI target driver, which has hardware at the other end of the SCSI bus), is called to save and restore its state if it exports a pm-hardware-state property with the value needs-suspend-resume. Otherwise, the lack of a reg property is taken to mean that the device has no hardware state. For information on device properties, see Chapter 4, Properties and Events.

A device that has a reg property but no hardware state may export a pm-hardware-state property with the value no-suspend-resume to keep the framework from calling into the driver to save and restore that state. For more information on power management properties, see the pm-components(9P) man page.

Automatic Power Management for Systems

The system will be shut down if the following conditions apply:

Entry Points Used by System Power Management

System power management passes the command DDI_SUSPEND to the detach(9E) driver entry point to request the driver to save the device hardware state. It passes the command DDI_RESUME to the attach(9E) driver entry point to request the driver to restore the device hardware state.

detach() Entry Point

The syntax for detach(9E) is as follows:

    int detach(dev_info_t *dip, ddi_detach_cmd_t cmd);

If a device has a reg property or a pm-hardware-state property with a value of needs-suspend-resume, then the framework calls into the driver's detach(9E) entry point to allow the driver to save the hardware state of the device to memory so that it can be restored after the system power returns. To process the DDI_SUSPEND command, detach(9E) must do the following:

If for some reason the driver is not able to suspend the device and save its state to memory, then it must return DDI_FAILURE, and the framework aborts the system power management operation.

In some cases, powering down a device involves certain risks. For example, if a tape drive is powered off with a tape inside it, the tape can be damaged. In such a case, attach(9E) should:

If both of these are true, the DDI_SUSPEND request should be rejected. Example 9–6 shows an example of an attach(9E) routine using ddi_removing_power(9F) to check whether a DDI_SUSPEND causes problems.

Dump requests must be honored. The framework uses the dump(9E) entry point to write out the state file containing the contents of memory. See the dump(9E) man page for restrictions imposed on the device driver when using this entry point.

If the device implements power-manageable components, the device may have had its state saved and powered off when its detach(9E) entry point is called with the DDI_SUSPEND command. In this case the driver should cancel pending timeouts and suppress the call to pm_raise_power(9F) (except for dump(9E) requests) until the device is resumed by a call to attach(9E) with a command of DDI_RESUME. The driver must keep sufficient track of its state to be able to deal appropriately with this possibility. Example 9–6 shows an example of a detach(9E) routine with the DDI_SUSPEND command implemented.


Example 9–6 detach(9E) Routine Implementing DDI_SUSPEND

int
xxdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
        struct xxstate *xsp;
        int instance;

        instance = ddi_get_instance(dip);
        xsp = ddi_get_soft_state(statep, instance);

        switch (cmd) {
        case DDI_DETACH:
          ...

        case DDI_SUSPEND:
               /*
                * We do not allow DDI_SUSPEND if power will be removed and
                * we have a device that damages tape when power is removed
                * We do support DDI_SUSPEND for Device Reconfiguration.
.
                */
                  if (ddi_removing_power(dip) && xxdamages_tape(dip))
                     return (DDI_FAILURE);

                mutex_enter(&xsp->mu);
                xsp->xx_suspended = 1;  /* stop new operations */

                /*
                 * Sleep waiting for all the commands to be completed
                 */
                ...

                /*
                 * If a callback is outstanding which cannot be cancelled
                 * then either wait for the callback to complete or fail the
                 * suspend request
                 */
                ...

                /*
                 * This section is only needed if the driver maintains a
                 * running timeout
                 */
                if (xsp->xx_timeout_id) {
                        timeout_id_t temp_timeout_id = xsp->xx_timeout_id;

                        xsp->xx_timeout_id = 0;
                        mutex_exit(&xsp->mu);
                        untimeout(temp_timeout_id);
                        mutex_enter(&xsp->mu);
                }

                if (!xsp->xx_state_saved) {
                        /*
                         * Save device register contents into
                         * xsp->xx_device_state
                         */
                        ...
                }
                mutex_exit(&xsp->mu);
                return (DDI_SUCCESS);

        default:
                return (DDI_FAILURE);
}

attach() Entry Point

The syntax for attach(9E) is as follows:

    int attach(dev_info_t *dip, ddi_attach_cmd_t cmd);

When power is restored to the system, each device with a reg property or with a pm-hardware-state property of value needs-suspend-resume has its attach(9E) entry point called with a command value of DDI_RESUME. If the system shutdown was aborted for some reason, each driver that was suspended is called to resume, even though the power has not been shut off. Consequently, the resume code in attach(9E) must make no assumptions about the state of the hardware; it may or may not have lost power.

The power management framework considers the power level of the components to be unknown at DDI_RESUME time. Depending on the nature of the device, the driver writer has two choices:

Example 9–7 shows an example of an attach(9E) routine with the DDI_RESUME command.


Example 9–7 attach(9E) Routine Implementing DDI_RESUME

int
xxattach(devinfo_t *dip, ddi_attach_cmd_t cmd)
{
        struct xxstate *xsp;
        int    instance;

        instance = ddi_get_instance(dip);
        xsp = ddi_get_soft_state(statep, instance);

        switch (cmd) {
        case DDI_ATTACH:
        ...

        case DDI_RESUME:
                mutex_enter(&xsp->mu);
                if (xsp->xx_pm_state_saved) {
                        /*
                         * Restore device register contents from
                         * xsp->xx_device_state
                         */
                        ...
                }
                /*
                 * This section is optional and only needed if the
                 * driver maintains a running timeout
                 */
                xsp->xx_timeout_id = timeout(...);

                xsp->xx_suspended = 0;          /* allow new operations */
                cv_broadcast(&xsp->xx_suspend_cv);

                /* If it is possible to determine in a device-specific 
                 * way what the power levels of components are without 
                 * powering the components up,
                 * then the following code is recommended
                 */
                for (i = 0; i < num_components; i++) {
                        xsp->xx_power_level[i] = xx_get_power_level(dip, i);
                        if (xsp->xx_power_level[i] != XX_LEVEL_UNKNOWN)
                                (void) pm_power_has_changed(dip, i, 
                                    xsp->xx_power_level[i]);
                }
                mutex_exit(&xsp->mu);
                return(DDI_SUCCESS);
        default:
                return(DDI_FAILURE);
        }
}


Note –

The detach(9E) and attach(9E) interfaces may also be used to resume a system that has been quiesced.


Power Management Device Access Example

If power management is supported, and detach(9E) and attach(9E) have code such as shown in the previous examples, the code fragment in Example 9–8 can be used where device access is about to be made to the device from user context (for example, in read(2), write(2), ioctl(2)).

The following example assumes that the operation about to be performed requires a component component that is operating at power level level.


Example 9–8 Device Access

...
mutex_enter(&xsp->mu);
/*
 * Block command while device is suspeded via DDI_SUSPEND
 */
while (xsp->xx_suspended)
        cv_wait(&xsp->xx_suspend_cv, &xsp->mu);

/*
 * Mark component busy so power() will reject attempt to lower power
 */
xsp->xx_busy[component]++;
if (pm_busy_component(dip, component) != DDI_SUCCESS) {
        xsp->xx_busy[component]--;
        /*
         * Log error and abort
         */
        ....
}

if (xsp->xx_power_level[component] < level) {
        mutex_exit(&xsp->mu);
        if (pm_raise_power(dip, component, level) != DDI_SUCESS) {
                /*
                 * Log error and abort
                 */
                ...
        }
        mutex_enter(&xsp->mu);
}
...

The code fragment in Example 9–9 can be used when device operation completes (for example, in the device's interrupt handler).


Example 9–9 Device Operation Completion

...
/*
 * For each command completion, decrement the busy count and unstack
 * the pm_busy_component() call by calling pm_idle_component(). This
 * will allow device power to be lowered when all commands complete
 * (all pm_busy_component() counts are unstacked)
 */
xsp->xx_busy[component]--;
if (pm_idle_component(dip, component) != DDI_SUCCESS) {
        xsp->xx_busy[component]++;
        /*
         * Log error and abort
         */
        ....
}

/*
 * If no more outstanding commands, wake up anyone (like DDI_SUSPEND)
 * waiting for all commands to  be completed
 */
...

Power Management Flow of Control

Figure 9–1 illustrates the flow of control in the power management framework.

When a component's activity is complete, a driver can call pm_idle_component(9F) to mark the component as idle. When the component has been idle for its threshold time, the framework may lower the power of the component to its next lower level. The framework does this by calling the power(9E) function to set the power level of the component to its next lower supported power level (if any). The driver's power(9E) function should reject any attempt to lower the power level of a component when it is busy. The driver's power(9E) function should also save any state that will be lost as a result of the transition to the lower power level before making that transition.

When the component is needed again at a higher power level, the driver calls pm_busy_component(9F) to keep the framework from lowering the power still further, and then calls pm_raise_power(9F) on the component. The framework then calls power(9E) to raise the power of the component (before the call to pm_raise_power(9F) returns). The driver's power(9E) code must restore any state that was lost in the lower level but is needed in the higher level after making the power transition.

When a driver is detaching, it should call pm_lower_power(9F) for each component to lower its power to its lowest level. The framework may then call into the driver's power(9E) routine (before the call to pm_lower_power(9F) returns) to lower the power of the component.

Figure 9–1 Power Management Conceptual State Diagram

Diagram shows the flow of control through power management routines.

Changes to Power Management Interfaces

Previous to the Solaris 8 release, power management of devices was not automatic. It was necessary to add an entry to /etc/power.conf for each device that was to be power managed.

The framework assumed that all devices supported only two power levels: 0 and full (“normal”) power.

There was an implied dependency of all other components on component 0. Whenever component 0 changed to or from level 0, a call was made into the driver's detach(9E) or attach(9E) routine with commands DDI_PM_SUSPEND and DDI_PM_RESUME respectively to save and restore hardware state.

The old interfaces (including ddi_dev_is_needed(9F), pm_create_components(9F), pm_destroy_components(9F), pm_get_normal_power(9F), pm_set_normal_power(9F), DDI_PM_SUSPEND and DDI_PM_RESUME) are still supported for binary compatibility, but are obsolete.

As of the Solaris 8 release, devices which export the pm-components property are automatically power managed (if autopm is enabled).

The framework now knows from the pm-components property which power levels are supported by each device.

The framework makes no assumptions about dependencies among the different components of a device. The device driver is responsible for saving and restoring hardware state as needed when changing power levels.

These changes allow the power management framework to deal with emerging device technology, and result in greater power savings (since the framework can detect automatically which devices can save power, and can use intermediate power states of the devices), and allows the system to meet energy consumption goals without the entire system being powered down or functionality being lost.

Table 9–1 Power Management Interfaces

Old Interfaces 

Solaris 8 Interfaces 

pm_create_components(9E) 

pm-conponents(9) 

pm_set_normal_power(9F) 

pm-components(9) 

pm_destroy_components(9F) 

 

pm_get_normal_power(9E) 

 

ddi_dev_is_needed(9F) 

pm_raise_power(9F) 

 

pm_lower_power(9F 

 

pm_power_has_changed(9F) 

DDI_PM_SUSPEND 

 

DDI_PM_RESUME