Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
9.  Power Management System Power Management Model Entry Points Used by System Power Management detach() Entry Point  Previous   Contents   Next 
   
 

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:

  • If the driver can determine the actual power level of the components of the device without powering them up (by reading a register, for example), then the driver should notify the framework of the power level of each component by calling pm_power_has_changed(9F).

  • If it cannot determine the power levels of the components, then the driver should mark each component internally as unknown and call pm_raise_power(9F) before the first access to each one.

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
 */
...

 
 
 
  Previous   Contents   Next