Writing Device Drivers

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

detach()

	int detach(dev_info_t *dip, ddi_detach_cmd_t cmd);

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.

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 dump(9E) for restrictions imposed on the device driver when using this entry point.


Note -

The entry point dump(9E) was previously used only for writing kernel crash dumps to disk. It is now also used to write out the state file containing the information necessary to restore the system to its state prior to a system power management suspend.


If the device implements a power-manageable component zero, the device may already have been suspended and powered off using the command DDI_PM_SUSPEND when its detach(9E) entry point is called with the DDI_SUSPEND command. The additional processing necessary in this case is to cancel pending timeouts and suppress the call to ddi_dev_is_needed(9F) 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 8-4 shows an example of a detach(9E) routine with the DDI_SUSPEND command implemented.


Example 8-4 detach(9E) Routine Showing the Use of DDI_SUSPEND

int
xxdetach(devinfo_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:
	   	see chapter 5, Autoconfiguration for discussion

 	case DDI_SUSPEND:
	  	   mutex_enter(&xsp->mu);
	  	   xsp->xx_suspended = 1;	/* stop new operations */
	  	   if (!xsp->xx_pm_suspended) {
			   /*
			    * This code assumes that we'll get a cv_broadcast when
			    * we're no longer busy
			    */
			   while(xsp->xx_busy)	/* wait for pending ops */
					   cv_wait(&xsp->xx_busy_cv, &xsp->mu);
			Save device register contents into xsp->xx_device_state
				/*
				 * 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 optional, only needed if the driver maintains a running 	
			timeout (but be sure to drop the  mutex in any case)
			   /* cancel timeouts */
			   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);
			   } else {
				    mutex_exit(&xsp->mu);
			   }
	     	} else {
			      mutex_exit(&xsp->mu);
	   	}
	  	  return(DDI_SUCCESS);
 	case DDI_PM_SUSPEND:
	    	see Example 8-2 
 	default:
	    	return(DDI_FAILURE);
 	}
}

attach()

	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 resume code must restore the hardware state from the saved image in memory (possibly including reloading firmware), reregister any necessary timeouts, and unblock any pending requests.

Example 8-5 shows an example of an attach(9E) routine with the DDI_RESUME command.


Example 8-5 attach(9E) Routine Showing the Use of 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:
	    	see chapter 5, Autoconfiguration, for discussion

 	case DDI_RESUME:
	  	   mutex_enter(&xsp->mu);
	     	if (!xsp->xx_pm_suspended) {
			    Restore device register contents from xsp->xx_device_state}
			    this section is optional, only needed if the driver maintains a running timeout
			    /* restart timeouts */
			    xsp->xx_timeout_id = timeout({...});
	    	}
	  	   xsp->xx_suspended = 0;	/* allow new operations */
	    	cv_broadcast(&xsp->cv);
	   	mutex_exit(&xsp->mu);
	   	return(DDI_SUCCESS);

 	case DDI_PM_RESUME:
	    	see Example 8-3	   default:
	    	return(DDI_FAILURE);
 	}
}


Note -

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