Support for Policy Modules

Name

Support for Policy Modules -- closer integration with higher-level code

Synopsis

#include <cyg/power/power.h>

void power_set_policy_callback ( void (*)(PowerController*, PowerMode, PowerMode, PowerMode, PowerMode) callback );

void (*)(PowerController*, PowerMode, PowerMode, PowerMode, PowerMode) power_get_policy_callback (void);

CYG_ADDRWORD power_get_controller_policy_data ( PowerController* controller );

void power_set_controller_policy_data ( PowerController* controller , CYG_ADDRWORD data );

Policy Callbacks

The use of a separate thread to perform power mode changes in typical configurations can cause problems for some policy modules. Specifically, the policy module can request a mode change for the system as a whole or for an individual controller, but it does not know when the power management thread actually gets scheduled to run again and carry out the request. Although it would be possible for the policy module to perform some sort of polling, in general that is undesirable.

To avoid such problems the policy module can install a callback function using power_set_policy_callback. The current callback function can be retrieved using power_get_policy_callback. If a callback function has been installed then it will be called by the power management package whenever a power controller has been invoked to perform a mode change. The callback will be called in the context of the power management thread, so usually it will have to make use of thread synchronisation primitives to interact with the main policy module. It is passed five arguments:

  1. The power controller that has just been invoked to perform a mode change.

  2. The mode this controller was running at before the invocation.

  3. The current mode this controller is now running at.

  4. The desired mode before the power controller was invoked. Usually this will be the same as the current mode, unless the controller has decided for some reason that this was inappropriate.

  5. The current desired mode. This will differ from the previous argument only if there has was another call to power_set_mode or power_set_controller_mode while the power controller was being invoked, probably by the power controller itself.

A simple example of a policy callback function would be:

static void
power_callback(
    PowerController* controller,
    PowerMode old_mode,
    PowerMode new_mode,
    PowerMode old_desired_mode,
    powerMode new_desired_mode)
{
    printf("Power mode change: %s, %s -> %d\n",
        power_get_controller_id(controller),
        mode_to_string(old_mode),
        mode_to_string(new_mode));

    CYG_UNUSED_PARAM(PowerMode, old_desired_mode);
    CYG_UNUSED_PARAM(PowerMode, new_desired_mode);
}

int
main(int argc, char** argv)
{
    …
    power_set_policy_callback(&power_callback);
    …
}

If power_set_controller_mode_now is used to manipulate an individual controller the policy callback will not be invoked. This function may get called from any context including DSRs, and even if there is already a call to the policy callback happening in some other context, so invoking the callback would usually be unsafe.

If the power management package has not been configured to use a separate thread then power_set_mode and power_set_controller_mode will manipulate the power controllers immediately and invoke the policy callback afterwards. Therefore the policy callback will typically run in the same context as the main policy module.

Policy-specific Controller Data

Some policy modules may want to associate some additional data with each power controller. This could be achieved by for example maintaining a hash table or similar data structure, but for convenience the power management package allows higher-level code, typically the policy module, to store and retrieve one word of data in each power controller. The function power_set_controller_policy_data takes two arguments, a pointer to a power controller and a CYG_ADDRWORD of data: by appropriate use of casts this word could be an integer or a pointer to some data structure. The matching function power_get_controller_policy_data retrieves the word previously installed, and can be cast back to an integer or pointer. The default value for the policy data is 0.

For example the following code fragment stores a simple index value in each power controller. This could then be retrieved by the policy callback.

    unsigned int     i = 0;
    PowerController* controller;

    for (controller = &(__POWER__[0]);
         controller != &(__POWER_END__);
         controller++) {
        power_set_controller_policy_data(controller, (CYG_ADDRWORD) i++);
    }

Not all policy modules will require per-controller data. The configuration option CYGIMP_POWER_PROVIDE_POLICY_DATA can be used to control this functionality, thus avoiding wasting a small amount of memory inside each power controller structure.