Writing Device Drivers

Device Power Management Interfaces

A device driver that supports a device with power-manageable components must create a pm-components(9P) property. This property indicates to the system that the device has power-manageable components. pm-components also tells the system which power levels are available. The driver typically informs the system by calling ddi_prop_update_string_array(9F) from the driver's attach(9E) entry point. An alternative means of informing the system is from a driver.conf(4) file. 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 between the busy and idle states 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. The component is marked busy whenever an outstanding request to the drive exists. The component is marked idle when the last queued request finishes. Some components are created and never marked busy. For example, 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 pm_busy_component(9F) call has the following syntax:

int pm_busy_component(dev_info_t *dip, int component);

pm_busy_component(9F) marks component as busy. While the component is busy, that component should not be powered off. If the component is already powered off, then marking that component busy does not change the 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 pm_idle_component(9F) routine has the following syntax:

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. Setting the power level in this manner is necessary before using a component that has been powered off. For example, the read(9E) routine of a SCSI disk target driver might need to spin up the disk, if the disk has been powered off. The pm_raise_power(9F) function 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. Similarly, some disk drives have a limited tolerance for power cycles, because each cycle results in a head landing. Use the no-involuntary-power-cycles(9P) property to notify the system that the device driver should control all power cycles for the device. This approach 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) from its detach(9E) entry point.

The pm_raise_power(9F) function is called when the driver discovers that a component needed for some operation is at an insufficient power level. This interface causes the driver to raise the current power level of the component to the needed level. All the devices that depend on this device are also brought back to full power by this call.

Call the pm_lower_power(9F) function when the device is detaching once access to the device is no longer needed. Call pm_lower_power(9F) to set each component at the lowest power so that the device uses as little power as possible while not in use. The pm_lower_power() function must be called from the detach() entry point. The pm_lower_power() function has no effect if it is called from any other part of the driver.

The pm_power_has_changed(9F) function is called to notify the framework about a power transition. The transition might be due to the device changing its own power level. The transition might also be due to an operation such as suspend-resume. The syntax for pm_power_has_changed(9F) is the same as the syntax for pm_raise_power(9F).