blob: ce6608cdfcf7ca6d21a1058a5827cf398bd53b45 [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Draft Prototype of Protocols to be used by Power Broker.
// None of these protocols should be considered fully baked at this time
// and should be expected to change in the future as we gain information
// through this prototype testbed about coverage and usability.
@available(added=HEAD)
library fuchsia.power.broker;
using zx;
/// Used to describe the power level of an element.
/// Could extend this further to support additional types of power
/// levels, such as ACPI.
alias PowerLevel = uint8;
/// BinaryPowerLevel is a well-known set of PowerLevels with only two
/// states: OFF and ON.
type BinaryPowerLevel = strict enum : PowerLevel {
OFF = 0;
ON = 1;
};
type DependencyType = strict enum {
ACTIVE = 1;
PASSIVE = 2;
};
const MAX_ELEMENT_NAME_LEN uint16 = 1024;
/// A token that represents the right to add a dependency upon another
/// element. Should first be registered with Power Broker via
/// ElementControl.RegisterDependencyToken of the required element.
alias DependencyToken = zx.Handle:EVENT;
/// Power dependency from an already specified element's PowerLevel to another.
/// The dependent Element should already be known from context.
type LevelDependency = resource struct {
dependency_type DependencyType;
dependent_level PowerLevel;
/// Must supply a token registered via the RegisterDependencyToken call of
/// the required element's ElementControl protocol.
requires_token DependencyToken;
requires_level PowerLevel;
};
/// This is the primary initial protocol used by Power Element Owners to
/// communicate with Power Broker. Power Element Owners should add the
/// elements they own to the Power Topology through AddElement. All further
/// interactions with Power Broker are done through channels opened by the
/// AddElement call, which are scoped to the added element.
@discoverable
open protocol Topology {
/// Called by a Power Element owner to register a new Power Element and
/// open control channels for that element.
flexible AddElement(ElementSchema) -> (resource struct {
/// ElementControl channel for this element.
/// When this channel is dropped, the element will be removed from the
/// topology. All channels associated with this element will be
/// closed and all tokens registered to this element will be
/// unregistered.
element_control_channel client_end:ElementControl;
}) error AddElementError;
};
/// Passed to Topology.AddElement.
type ElementSchema = resource table {
/// Human-readable name for logging and debug purposes.
1: element_name string:MAX_ELEMENT_NAME_LEN;
/// The initial current power level of the element.
2: initial_current_level PowerLevel;
/// All power levels that are valid for this element. Any level not
/// specified here will be treated as invalid.
3: valid_levels vector<PowerLevel>:MAX_VALID_POWER_LEVELS;
/// List of dependencies for this element's power levels.
/// Note: dependencies UPON this element's levels cannot be added here.
4: dependencies vector<LevelDependency>:MAX_DEPENDENCIES_IN_ADD_ELEMENT;
/// List of active dependency tokens to register for this element.
/// These tokens will allow other element owners to create active
/// dependencies upon this element by passing them as the
/// requires_token of a LevelDependency.
5: active_dependency_tokens_to_register vector<DependencyToken>:MAX_TOKENS_IN_ADD_ELEMENT;
/// List of passive dependency tokens to register for this element.
/// These tokens will allow other element owners to create passive
/// dependencies upon this element by passing them as the
/// requires_token of a LevelDependency.
6: passive_dependency_tokens_to_register vector<DependencyToken>:MAX_TOKENS_IN_ADD_ELEMENT;
/// Channels on which Power Broker will send required power levels and
/// receive current level updates.
7: level_control_channels LevelControlChannels;
/// Optional. If passed, this will be treated as a consumer element and
/// Leases for this element can be requested via this channel.
8: lessor_channel server_end:Lessor;
};
type LevelControlChannels = resource struct {
/// Channel on which Power Broker will receive current level updates
/// for this element.
current server_end:CurrentLevel;
/// Channel on which Power Broker will send required power levels
/// for this element.
required server_end:RequiredLevel;
};
// Limitations on vector length for the sake of bounding request size.
const MAX_DEPENDENCIES_IN_ADD_ELEMENT uint16 = 128;
const MAX_TOKENS_IN_ADD_ELEMENT uint16 = 128;
const MAX_VALID_POWER_LEVELS uint16 = 256;
type AddElementError = flexible enum {
INTERNAL = 1;
INVALID = 2;
NOT_AUTHORIZED = 3;
};
/// Provides element-scoped access to an element previously added via
/// Topology.AddElement.
open protocol ElementControl {
/// Register a new Status channel on which Power Broker will send
/// read-only updates of the element's current power level. This method
/// is intended to allow element owners to give read-only access to the
/// element's current power level to clients by opening and transferring
/// this channel.
flexible OpenStatusChannel(resource struct {
status_channel server_end:Status;
});
/// Adds an active or passive dependency of this element upon another
/// element.
flexible AddDependency(LevelDependency) -> () error ModifyDependencyError;
/// Removes an active or passive dependency of this element upon another
/// element.
flexible RemoveDependency(LevelDependency) -> () error ModifyDependencyError;
/// Register a token which will permit the bearer to add either an
/// active or passive dependency upon this element, depending on the
/// dependency_type specified.
flexible RegisterDependencyToken(resource struct {
token DependencyToken;
dependency_type DependencyType;
}) -> () error RegisterDependencyTokenError;
/// Unregister a token previously registered via RegisterDependencyToken.
flexible UnregisterDependencyToken(resource struct {
token DependencyToken;
}) -> () error UnregisterDependencyTokenError;
};
type ModifyDependencyError = flexible enum {
ALREADY_EXISTS = 1;
INVALID = 2;
NOT_AUTHORIZED = 3;
NOT_FOUND = 4;
};
type RegisterDependencyTokenError = flexible enum {
ALREADY_IN_USE = 1;
INTERNAL = 2;
};
type UnregisterDependencyTokenError = flexible enum {
NOT_AUTHORIZED = 1;
NOT_FOUND = 2;
};
/// Element Permissions
type Permissions = strict bits : uint32 {
MODIFY_ACTIVE_DEPENDENT = 0b00000001;
MODIFY_PASSIVE_DEPENDENT = 0b0000010;
MODIFY_DEPENDENCY = 0b00000100;
};
/// CurrentLevel and RequiredLevel must both be used by all managed
/// Power Elements as part of the power level handshake with Power Broker:
/// * The element operator calls RequiredLevel.Watch to receive the next
/// required level from Power Broker.
/// * The operator makes the changes necessary to transition to the new
/// required level.
/// * The operator calls CurrentLevel.Update to inform Power Broker
/// that it has completed the transition to the new level.
/// Established via Topology.AddElement.
open protocol CurrentLevel {
/// Sent by the element on initial startup and whenever there is a change
/// in power level.
flexible Update(resource struct {
current_level PowerLevel;
}) -> () error CurrentLevelError;
};
type CurrentLevelError = flexible enum {
NOT_AUTHORIZED = 1;
};
/// Part of the power level handshake with Power Broker used for receiving
/// required levels from Power Broker. See above note on CurrentLevel.
/// Established via Topology.AddElement.
open protocol RequiredLevel {
/// Returns the required power level for this element. The first call on
/// this channel will return immediately. Subsequent calls will block until
/// the required power level has changed.
flexible Watch() -> (resource struct {
required_level PowerLevel;
}) error RequiredLevelError;
};
type RequiredLevelError = flexible enum {
INTERNAL = 1;
NOT_AUTHORIZED = 2;
UNKNOWN = 3;
};
// Unique ID provided by Power Broker (currently a UUID but subject to change).
alias LeaseId = string:64;
/// Provides element-scoped access to request leases to raise the levels of an
/// element previously added via Topology.AddElement.
open protocol Lessor {
/// Request made to indicate client intends to raise the given element
/// to the given power level and wants to have its direct and transitive
/// power dependencies satisfied.
flexible Lease(resource struct {
/// Power level of this element to be raised to.
level PowerLevel;
}) -> (resource struct {
/// Channel for actions to be taken on the lease.
/// When this channel is closed, the lease will be dropped.
lease_control client_end:LeaseControl;
}) error LeaseError;
};
type LeaseError = flexible enum {
INTERNAL = 1;
NOT_AUTHORIZED = 2;
};
type LeaseStatus = flexible enum {
UNKNOWN = 0;
PENDING = 1;
SATISFIED = 2;
};
/// Provides lease-scoped access to actions that can be taken on a lease
/// previously acquired via Lessor.Lease. Closing this control channel drops
/// the lease.
/// TODO(https://fxbug.dev/339474151): Switch from a protocol to an eventpair.
open protocol LeaseControl {
/// Get the current status of the lease.
/// If last_status is UNKNOWN, the call will return immediately
/// with the current status. Otherwise, the call will block
/// until the current status differs from last_status.
flexible WatchStatus(struct {
last_status LeaseStatus;
}) -> (struct {
status LeaseStatus;
});
};
/// Provides read-only access to the current PowerLevel of an element and the
/// ability to watch changes to an element's power level. A new channel to
/// this protocol can be obtained by calling OpenStatus on the element's
/// ElementControl channel (and passed to other clients who need access
/// to the element's current power level).
open protocol Status {
/// Returns the current power level for this element. The first call on
/// this channel will return immediately. Subsequent calls will block until
/// the current power level has changed.
flexible WatchPowerLevel() -> (resource struct {
current_level PowerLevel;
}) error StatusError;
};
type StatusError = flexible enum {
UNKNOWN = 1;
};
/// PowerLevel name lengths are limited to reduce Inspect space usage
const MAX_LEVEL_NAME_LEN uint16 = 16;
/// Status client endpoint and a plaintext name for a specific Power Element. Names are
/// expected to be unique between elements and persistent across reboots of the same build,
/// but consistency is not guaranteed between different builds.
type ElementStatusEndpoint = resource table {
1: identifier string:MAX_ELEMENT_NAME_LEN;
2: status client_end:Status;
};
/// Mapping of a plaintext name to a PowerLevel. Names are expected to be unique between
/// elements and persistent across reboots of the same build, but consistency is not
/// guaranteed between different builds.
type PowerLevelName = table {
1: level PowerLevel;
2: name string:MAX_LEVEL_NAME_LEN;
};
/// Mapping of a vector of [`fuchsia.power.broker/PowerLevelName`] to a Power Element via
/// its plaintext name. Names are expected to be unique between elements and persistent
/// across reboots of the same build, but consistency is not guaranteed between different builds.
type ElementPowerLevelNames = table {
1: identifier string:MAX_ELEMENT_NAME_LEN;
2: levels vector<PowerLevelName>:MAX_VALID_POWER_LEVELS;
};
/// Provides an interface to retrieve information about PowerElements managed by a component.
@discoverable
open protocol ElementInfoProvider {
/// Returns mappings of PowerLevels to plaintext names for each element managed
/// by a component. Returns an error if no mappings can be returned.
flexible GetElementPowerLevelNames() -> (resource struct {
level_names vector<ElementPowerLevelNames>:MAX;
}) error ElementInfoProviderError;
/// Returns available Status client endpoints and stable identifiers for each
/// element managed by a component. Returns an error if no endpoints can be
/// returned (i.e. no elements were able to implement the Status channel).
flexible GetStatusEndpoints() -> (resource struct {
endpoints vector<ElementStatusEndpoint>:MAX;
}) error ElementInfoProviderError;
};
type ElementInfoProviderError = flexible enum {
UNKNOWN = 0;
FAILED = 1;
};
service ElementInfoProviderService {
status_provider client_end:ElementInfoProvider;
};