diff --git a/module/scmi_telemetry/CMakeLists.txt b/module/scmi_telemetry/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..c43bcf5b97c37567c58dbd114f7ee63525b3df20 --- /dev/null +++ b/module/scmi_telemetry/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2025, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +add_library(${SCP_MODULE_TARGET} SCP_MODULE) + +target_include_directories(${SCP_MODULE_TARGET} + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") + +target_sources( + ${SCP_MODULE_TARGET} + PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/mod_scmi_telemetry.c") + +target_link_libraries(${SCP_MODULE_TARGET} PRIVATE module-telemetry) + +target_link_libraries(${SCP_MODULE_TARGET} PRIVATE module-scmi) + +if("resource-perms" IN_LIST SCP_MODULES) + target_link_libraries(${SCP_MODULE_TARGET} PRIVATE module-resource-perms) +endif() diff --git a/module/scmi_telemetry/Module.cmake b/module/scmi_telemetry/Module.cmake new file mode 100644 index 0000000000000000000000000000000000000000..b9f474c8b3d26a6b37105d7585c72d5e5e7be0d4 --- /dev/null +++ b/module/scmi_telemetry/Module.cmake @@ -0,0 +1,9 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2025, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +set(SCP_MODULE "scmi-telemetry") +set(SCP_MODULE_TARGET "module-scmi-telemetry") diff --git a/module/scmi_telemetry/include/internal/scmi_telemetry.h b/module/scmi_telemetry/include/internal/scmi_telemetry.h new file mode 100644 index 0000000000000000000000000000000000000000..d0c62828ec022fcbb53e0c674dea4f7ccce6daaa --- /dev/null +++ b/module/scmi_telemetry/include/internal/scmi_telemetry.h @@ -0,0 +1,668 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * System Control and Management Interface (SCMI) support for Telemetry + * Management Protocol. + */ + +#ifndef INTERNAL_SCMI_TELEMETRY_H +#define INTERNAL_SCMI_TELEMETRY_H + +#include + +#include + +#include + +/*! + * \addtogroup GroupModules Modules + * \{ + */ + +/*! + * \defgroup GroupSCMI_TELEMETRY SCMI Telemetry Protocol. + * \{ + */ + +#define SCMI_PROTOCOL_VERSION_TELEMETRY UINT32_C(0x10000) + +/* + * NEGOTIATE_PROTOCOL_VERSION + */ +struct scmi_telemetry_negotiate_protocol_version_a2p { + uint32_t version; +}; + +/* + * PROTOCOL_ATTRIBUTES + */ + +/* + * SCMI Telemetry Protocol Attributes Macros + * + * These macros define bit positions and masks for encoding various attributes + * of the SCMI (System Control and Management Interface) Telemetry protocol. + * These attributes help describe the protocol capabilities and behaviors. + */ + +/* Bit position indicating support for asynchronous telemetry read operations */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_ASYNC_READ_POS 31 + +/* Bit position indicating support for continuous telemetry updates */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_CONTINUOUS_UPDATE_POS 30 + +/* Bit position indicating whether telemetry reset is supported */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_TELEMETRY_RESET_POS 17 + +/* Bit position indicating Fast Channel (FCH) support */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_FCH_POS 16 + +/* Bit position indicating the number of available Shared Memory Telemetry + * Interfaces (SHMTI) */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_NUM_SHMTI_POS 0 + +/* + * SCMI_TELEMETRY_PROTOCOL_ATTR_ASYNC_READ_MASK + * + * Mask for enabling or disabling asynchronous telemetry reading. + * When set, this indicates that telemetry data can be read asynchronously. + */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_ASYNC_READ_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_PROTOCOL_ATTR_ASYNC_READ_POS) + +/* + * SCMI_TELEMETRY_PROTOCOL_ATTR_CONTINUOUS_UPDATE_MASK + * + * Mask for enabling or disabling continuous updates. + * When set, this indicates that telemetry data is updated continuously. + */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_CONTINUOUS_UPDATE_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_PROTOCOL_ATTR_CONTINUOUS_UPDATE_POS) + +/* + * SCMI_TELEMETRY_PROTOCOL_ATTR_NUM_SHMTI_MASK + * + * Mask to extract or set the number of Shared Memory Telemetry Interfaces + * (SHMTI). This defines how many SHMTI instances are available. + */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_NUM_SHMTI_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_PROTOCOL_ATTR_NUM_SHMTI_POS) + +/* + * SCMI_TELEMETRY_PROTOCOL_ATTR_TELEMETRY_RESET_MASK + * + * Mask indicating whether telemetry reset is supported. + * When set, the protocol supports resetting telemetry data. + */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_TELEMETRY_RESET_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_PROTOCOL_ATTR_TELEMETRY_RESET_POS) + +/* + * SCMI_TELEMETRY_PROTOCOL_ATTR_FCH_MASK + * + * Mask indicating support for Fast Channel (FCH) + * functionality. This feature allows better frequency coordination across + * multiple components. + */ +#define SCMI_TELEMETRY_PROTOCOL_ATTR_FCH_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_PROTOCOL_ATTR_FCH_POS) + +/* + * SCMI_TELEMETRY_PROTOCOL_ATTRIBUTES + * + * Macro to encode SCMI Telemetry Protocol attributes into a single 32-bit + * value. This macro shifts and combines various flags and values to form the + * protocol attributes. + * + * Parameters: + * - ASYNC: Enables asynchronous telemetry data reading (1 = enabled, 0 = + * disabled). + * - CONTINUOUS_UPDATE: Enables continuous telemetry updates (1 = enabled, 0 = + * disabled). + * - TELEMETRY_RESET: Indicates whether telemetry reset is supported (1 = + * supported, 0 = not supported). + * - FCH: Enables Fast Channel support (1 = enabled, 0 = + * disabled). + * - NUM_SHMTI: Specifies the number of available SHMTI instances. + * + * Returns: + * - A 32-bit encoded value representing the protocol attributes. + */ +#define SCMI_TELEMETRY_PROTOCOL_ATTRIBUTES( \ + ASYNC, CONTINUOUS_UPDATE, TELEMETRY_RESET, FCH, NUM_SHMTI) \ + ( \ + (((ASYNC) << SCMI_TELEMETRY_PROTOCOL_ATTR_ASYNC_READ_POS) & \ + SCMI_TELEMETRY_PROTOCOL_ATTR_ASYNC_READ_MASK) | \ + (((CONTINUOUS_UPDATE) \ + << SCMI_TELEMETRY_PROTOCOL_ATTR_CONTINUOUS_UPDATE_POS) & \ + SCMI_TELEMETRY_PROTOCOL_ATTR_CONTINUOUS_UPDATE_MASK) | \ + (((TELEMETRY_RESET) \ + << SCMI_TELEMETRY_PROTOCOL_ATTR_TELEMETRY_RESET_POS) & \ + SCMI_TELEMETRY_PROTOCOL_ATTR_TELEMETRY_RESET_MASK) | \ + (((FCH) << SCMI_TELEMETRY_PROTOCOL_ATTR_FCH_POS) & \ + SCMI_TELEMETRY_PROTOCOL_ATTR_FCH_MASK) | \ + (((NUM_SHMTI) << SCMI_TELEMETRY_PROTOCOL_ATTR_NUM_SHMTI_POS) & \ + SCMI_TELEMETRY_PROTOCOL_ATTR_NUM_SHMTI_MASK)) +/*! + * \brief SCMI Telemetry Protocol Attributes Response Structure + * + * This structure is used to return protocol attributes when handling + * an SCMI protocol attributes request. + */ +struct scmi_telemetry_protocol_attributes_p2a { + /*! Status of the SCMI request (SCMI_SUCCESS, SCMI_NOT_FOUND, etc.) */ + int32_t status; + + /*! Total number of Data Event (DE) descriptors available */ + uint32_t num_de; + + /*! Encoded attribute flags representing protocol capabilities */ + uint32_t attributes; +}; + +/*! + * \brief SCMI Telemetry List SHMTI (Shared Memory Telemetry Interface) + * + * This section defines macros and structures for handling SHMTI in the SCMI + * Telemetry protocol. The SHMTI region provides shared memory interfaces + * for telemetry data storage. + */ + +/* Bit position for the number of remaining SHMTI instances */ +#define SCMI_TELEMETRY_LIST_SHMTI_NUM_REMAIN_POS 16 + +/* Bit position for the number of SHMTI instances in the response */ +#define SCMI_TELEMETRY_LIST_SHMTI_NUM_POS 0 + +/* Mask for extracting the number of remaining SHMTI instances */ +#define SCMI_TELEMETRY_LIST_SHMTI_NUM_REMAIN_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_LIST_SHMTI_NUM_REMAIN_POS) + +/* Mask for extracting the number of SHMTI instances in the response */ +#define SCMI_TELEMETRY_LIST_SHMTI_NUM_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_LIST_SHMTI_NUM_POS) + +/*! + * \brief Compute the total number of SHMTI instances in the response. + * + * \param[in] REMAIN The number of remaining SHMTI instances. + * \param[in] CURRENT The number of SHMTI instances in the current response. + * + * \return A 32-bit value encoding the total number of SHMTI instances. + */ +#define SCMI_TELEMETRY_LIST_SHMTI_TOTAL_SHMTI(REMAIN, CURRENT) \ + ((((REMAIN) << SCMI_TELEMETRY_LIST_SHMTI_NUM_REMAIN_POS) & \ + SCMI_TELEMETRY_LIST_SHMTI_NUM_REMAIN_MASK) | \ + (((CURRENT) << SCMI_TELEMETRY_LIST_SHMTI_NUM_POS) & \ + SCMI_TELEMETRY_LIST_SHMTI_NUM_MASK)) + +/*! + * \brief SCMI response structure for listing SHMTI instances. + * + * This structure is used in the SCMI Telemetry List SHMTI response, + * containing the number of available SHMTI instances and their descriptors. + */ +struct scmi_telemetry_list_shmti_p2a { + int32_t status; /*!< Status of the SCMI request (SCMI_SUCCESS, etc.) */ + uint32_t num_shmti; /*!< Number of SHMTI instances in the response */ + struct mod_telemetry_shmti_desc + shmti_desc[]; /*!< Array of SHMTI descriptors */ +}; + +/*! + * \brief SCMI Telemetry Data Event (DE) Description + * + * This section defines macros and structures related to telemetry + * data event descriptions in the SCMI protocol. These descriptions + * help configure and retrieve telemetry data. + */ + +/* Bit positions for the number of DE descriptors remaining and current count */ +#define SCMI_TELEMETRY_DE_DESC_NUM_REMAIN_POS 16 +#define SCMI_TELEMETRY_DE_DESC_NUM_POS 0 + +/* Bit masks for extracting DE descriptor counts */ +#define SCMI_TELEMETRY_DE_DESC_NUM_REMAIN_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_DE_DESC_NUM_REMAIN_POS) +#define SCMI_TELEMETRY_DE_DESC_NUM_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_DE_DESC_NUM_POS) + +/*! + * \brief Compute the total number of DE descriptors in the response. + * + * \param[in] REMAIN The number of remaining DE descriptors. + * \param[in] CURRENT The number of DE descriptors in the current response. + * + * \return A 32-bit value encoding the total number of DE descriptors. + */ +#define SCMI_TELEMETRY_DE_DESC_TOTAL(REMAIN, CURRENT) \ + ((((CURRENT) << SCMI_TELEMETRY_DE_DESC_NUM_POS) & \ + SCMI_TELEMETRY_DE_DESC_NUM_MASK) | \ + (((REMAIN) << SCMI_TELEMETRY_DE_DESC_NUM_REMAIN_POS) & \ + SCMI_TELEMETRY_DE_DESC_NUM_REMAIN_MASK)) + +/*! + * \brief Bit positions for DE attribute fields in `de_attributes_1` + */ +#define SCMI_TELEMETRY_DE_FCH_POS 30 +#define SCMI_TELEMETRY_DE_TYPE_POS 22 +#define SCMI_TELEMETRY_DE_PERSISTENT_POS 21 +#define SCMI_TELEMETRY_DE_UNIT_EXP_POS 13 +#define SCMI_TELEMETRY_DE_UNIT_POS 5 +#define SCMI_TELEMETRY_DE_TIMESTAMP_EXP_POS 1 +#define SCMI_TELEMETRY_DE_TIMESTAMP_SUPPORT_POS 0 + +/* Bit masks for `de_attributes_1` */ +#define SCMI_TELEMETRY_DE_FCH_MASK (UINT32_C(0x1) << SCMI_TELEMETRY_DE_FCH_POS) +#define SCMI_TELEMETRY_DE_TYPE_MASK \ + (UINT32_C(0xFF) << SCMI_TELEMETRY_DE_TYPE_POS) +#define SCMI_TELEMETRY_DE_PERSISTENT_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_DE_PERSISTENT_POS) +#define SCMI_TELEMETRY_DE_UNIT_EXP_MASK \ + (UINT32_C(0xFF) << SCMI_TELEMETRY_DE_UNIT_EXP_POS) +#define SCMI_TELEMETRY_DE_UNIT_MASK \ + (UINT32_C(0xFF) << SCMI_TELEMETRY_DE_UNIT_POS) +#define SCMI_TELEMETRY_DE_TIMESTAMP_EXP_MASK \ + (UINT32_C(0xF) << SCMI_TELEMETRY_DE_TIMESTAMP_EXP_POS) +#define SCMI_TELEMETRY_DE_TIMESTAMP_SUPPORT_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_DE_TIMESTAMP_SUPPORT_POS) + +/*! + * \brief Macro to construct `de_attributes_1` field. + * + * \param[in] DE_FCH Fast Channel (1/0) + * \param[in] DE_TYPE Type of Data Event + * \param[in] DE_PERSISTENT Indicates persistent storage (1/0) + * \param[in] DE_UNIT_EXP Exponent value for unit + * \param[in] DE_UNIT Unit identifier + * \param[in] TS_EXP Exponent for timestamp granularity + * \param[in] TS_SUPPORT Timestamp support flag (1/0) + * + * \return Encoded `de_attributes_1` field. + */ +#define SCMI_TELEMETRY_DE_ATTR_1( \ + DE_FCH, DE_TYPE, DE_PERSISTENT, DE_UNIT_EXP, DE_UNIT, TS_EXP, TS_SUPPORT) \ + ((((DE_FCH) << SCMI_TELEMETRY_DE_FCH_POS) & SCMI_TELEMETRY_DE_FCH_MASK) | \ + (((DE_TYPE) << SCMI_TELEMETRY_DE_TYPE_POS) & \ + SCMI_TELEMETRY_DE_TYPE_MASK) | \ + (((DE_PERSISTENT) << SCMI_TELEMETRY_DE_PERSISTENT_POS) & \ + SCMI_TELEMETRY_DE_PERSISTENT_MASK) | \ + (((DE_UNIT_EXP) << SCMI_TELEMETRY_DE_UNIT_EXP_POS) & \ + SCMI_TELEMETRY_DE_UNIT_EXP_MASK) | \ + (((DE_UNIT) << SCMI_TELEMETRY_DE_UNIT_POS) & \ + SCMI_TELEMETRY_DE_UNIT_MASK) | \ + (((TS_EXP) << SCMI_TELEMETRY_DE_TIMESTAMP_EXP_POS) & \ + SCMI_TELEMETRY_DE_TIMESTAMP_EXP_MASK) | \ + (((TS_SUPPORT) << SCMI_TELEMETRY_DE_TIMESTAMP_SUPPORT_POS) & \ + SCMI_TELEMETRY_DE_TIMESTAMP_SUPPORT_MASK)) + +/*! + * \brief Bit positions for DE attribute fields in `de_attributes_2` + */ +#define SCMI_TELEMETRY_DE_INSTANCE_ID_POS 24 +#define SCMI_TELEMETRY_DE_COMP_INSTANCE_ID_POS 8 +#define SCMI_TELEMETRY_DE_COMP_TYPE_POS 0 + +/* Bit masks for `de_attributes_2` */ +#define SCMI_TELEMETRY_DE_INSTANCE_ID_MASK \ + (UINT32_C(0xFF) << SCMI_TELEMETRY_DE_INSTANCE_ID_POS) +#define SCMI_TELEMETRY_DE_COMP_INSTANCE_ID_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_DE_COMP_INSTANCE_ID_POS) +#define SCMI_TELEMETRY_DE_COMP_TYPE_MASK \ + (UINT32_C(0xFF) << SCMI_TELEMETRY_DE_COMP_TYPE_POS) + +/*! + * \brief Macro to construct `de_attributes_2` field. + * + * \param[in] DE_INSTANCE_ID Unique instance ID + * \param[in] DE_COMP_INSTANCE_ID Component instance ID + * \param[in] DE_COMP_TYPE Component type identifier + * + * \return Encoded `de_attributes_2` field. + */ +#define SCMI_TELEMETRY_DE_ATTR_2( \ + DE_INSTANCE_ID, DE_COMP_INSTANCE_ID, DE_COMP_TYPE) \ + ((((DE_INSTANCE_ID) << SCMI_TELEMETRY_DE_INSTANCE_ID_POS) & \ + SCMI_TELEMETRY_DE_INSTANCE_ID_MASK) | \ + (((DE_COMP_INSTANCE_ID) << SCMI_TELEMETRY_DE_COMP_INSTANCE_ID_POS) & \ + SCMI_TELEMETRY_DE_COMP_INSTANCE_ID_MASK) | \ + (((DE_COMP_TYPE) << SCMI_TELEMETRY_DE_COMP_TYPE_POS) & \ + SCMI_TELEMETRY_DE_COMP_TYPE_MASK)) + +/*! + * \brief SCMI response structure for DE descriptions. + * + * This structure is used in the SCMI Telemetry DE Description response, + * containing the number of available DE descriptions and their descriptors. + */ +struct scmi_telemetry_de_desc_p2a { + int status; /*!< Status of the SCMI request */ + uint32_t num_desc; /*!< Number of DE descriptions in the response */ + struct mod_telemetry_de_desc de_desc[]; /*!< Array of DE descriptors */ +}; + +/*! + * \brief SCMI Telemetry Update Intervals + * + * Defines macros and structures to represent telemetry update intervals + * in the SCMI telemetry protocol. These intervals determine how often + * telemetry data is refreshed. + */ + +/* Bit positions for the update interval fields */ +#define SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_REMAIN_POS \ + 16 /*!< Remaining intervals */ +#define SCMI_TELEMETRY_UPDATE_INTERVALS_FORMAT_POS \ + 12 /*!< Format of the interval */ +#define SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_POS 0 /*!< Number of intervals */ + +/* Bit masks for extracting interval properties */ +#define SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_REMAIN_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_REMAIN_POS) +#define SCMI_TELEMETRY_UPDATE_INTERVALS_FORMAT_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_UPDATE_INTERVALS_FORMAT_POS) +#define SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_MASK \ + (UINT32_C(0xFFF) << SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_POS) + +/*! + * \brief Constructs a telemetry update interval flag. + * + * \param[in] NUM_REMAIN Number of remaining update intervals. + * \param[in] INTERVAL_FORMAT Format of the update intervals (Discrete/Linear). + * \param[in] NUM_INTERVALS Number of update intervals in this response. + * + * \return Encoded update interval flag. + */ +#define SCMI_TELEMETRY_UPDATE_INTERVALS_FLAG( \ + NUM_REMAIN, INTERVAL_FORMAT, NUM_INTERVALS) \ + ((((NUM_REMAIN) << SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_REMAIN_POS) & \ + SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_REMAIN_MASK) | \ + (((INTERVAL_FORMAT) << SCMI_TELEMETRY_UPDATE_INTERVALS_FORMAT_POS) & \ + SCMI_TELEMETRY_UPDATE_INTERVALS_FORMAT_MASK) | \ + (((NUM_INTERVALS) << SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_POS) & \ + SCMI_TELEMETRY_UPDATE_INTERVALS_NUM_MASK)) + +/*! + * \brief SCMI response structure for telemetry update intervals. + * + * This structure is used in the SCMI telemetry response to provide + * a list of available update intervals. + */ +struct scmi_telemetry_list_update_intervals_p2a { + int32_t status; /*!< Status of the SCMI request (SCMI_SUCCESS, etc.) */ + uint32_t flags; /*!< Encoded flags representing update intervals */ +}; + +/*! + * \brief SCMI Telemetry Data Event (DE) Configuration + * + * Defines macros and structures for configuring Data Events (DE) + * in the SCMI telemetry protocol. + */ + +/*! + * \brief Data Event (DE) Modes + * + * These modes specify whether a Data Event is enabled, disabled, + * or enabled with a timestamp. + */ + +#define SCMI_TELEMETRY_DE_DISABLE 0 /*!< Disable Data Event */ +#define SCMI_TELEMETRY_DE_ENABLE_NON_TS \ + 1 /*!< Enable Data Event without timestamp */ +#define SCMI_TELEMETRY_DE_ENABLE_TS 2 /*!< Enable Data Event with timestamp */ + +/*! + * \brief SHMTI ID Constants + * + * These constants indicate unavailable or unsupported SHMTI IDs. + */ +#define SCMI_TELEMETRY_DE_SHMTI_ID_NOT_SUPPORTED UINT32_C(0xFFFFFFFF) +#define SCMI_TELEMETRY_DE_SHMTI_ID_OFFSET_NOT_SUPPORTED UINT32_C(0xFFFFFFFF) + +/*! + * \brief Bit positions and masks for DE configuration flags + */ +#define SCMI_TELEMETRY_DE_CONFIGURE_ALL_DE_DISABLE_POS \ + 2 /*!< Disable flag position */ +#define SCMI_TELEMETRY_DE_CONFIGURE_ALL_DE_DISABLE_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_DE_CONFIGURE_ALL_DE_DISABLE_POS) + +#define SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE_POS 0 /*!< Mode field position */ +#define SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE_MASK \ + (UINT32_C(0x3) \ + << SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE_POS) /*!< Uses 2 bits */ + +/*! + * \brief Check if all DEs are disabled + * + * \param[in] DE_CONFIGURE_FLAGS The flags to check. + * + * \return Nonzero if all DEs are disabled, zero otherwise. + */ +#define SCMI_TELEMETRY_ALL_DE_DISABLED(DE_CONFIGURE_FLAGS) \ + ((DE_CONFIGURE_FLAGS) & SCMI_TELEMETRY_DE_CONFIGURE_ALL_DE_DISABLE_MASK) + +/*! + * \brief Extract DE mode from configuration flags + * + * \param[in] DE_CONFIGURE_FLAGS The flags containing DE mode. + * + * \return The extracted DE mode. + */ +#define SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE(DE_CONFIGURE_FLAGS) \ + (((DE_CONFIGURE_FLAGS) & SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE_MASK) >> \ + SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE_POS) + +/*! + * \brief SHMTI ID Unavailable Constants + * + * These constants indicate that SHMTI IDs and offsets are unavailable. + */ +#define SCMI_TELEMETRY_SHMTI_ID_UNAVAILABLE UINT32_C(0xFFFFFFFF) +#define SCMI_TELEMETRY_SHMTI_ID_OFFSET_UNAVAILABLE UINT32_C(0xFFFFFFFF) + +/*! + * \brief SCMI request structure for DE configuration. + * + * This structure is used in SCMI requests to configure Data Events (DEs). + */ +struct scmi_telemetry_de_configure_a2p { + uint32_t de_id; /*!< ID of the Data Event to configure */ + uint32_t flags; /*!< Configuration flags (enable/disable/mode) */ +}; + +/*! + * \brief SCMI response structure for DE configuration. + * + * This structure is used in SCMI responses to indicate + * the status of a DE configuration request. + */ +struct scmi_telemetry_de_configure_p2a { + int32_t status; /*!< Status of the request (SCMI_SUCCESS, etc.) */ + uint32_t shmti_id; /*!< Assigned SHMTI ID for the Data Event */ + uint32_t shmti_de_offset; /*!< Offset of the Data Event within the SHMTI */ +}; + +/*! + * \brief SCMI Telemetry Enabled Data Events List + * + * Defines macros, enums, and structures used to retrieve a list of + * enabled Data Events (DE) in SCMI Telemetry. + */ + +/*! \brief Bit position and mask for the number of remaining DEs */ +#define SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_REMAIN_POS 16 +#define SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_REMAIN_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_REMAIN_POS) + +/*! \brief Bit position and mask for the number of DEs in response */ +#define SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_POS 0 +#define SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_POS) + +/*! + * \brief Macro to construct the enabled DE list flag. + * + * \param[in] NUM_REMAIN Number of remaining enabled DEs. + * \param[in] NUM_DE Number of DEs in the current response. + * + * \return Encoded flag representing the DE list response. + */ +#define SCMI_TELEMETRY_DE_ENABLED_LIST_FLAG(NUM_REMAIN, NUM_DE) \ + ((((NUM_REMAIN) << SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_REMAIN_POS) & \ + SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_REMAIN_MASK) | \ + (((NUM_DE) << SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_POS) & \ + SCMI_TELEMETRY_DE_ENABLED_LIST_NUM_MASK)) + +/*! + * \brief Enumeration for Data Event timestamp modes. + * + * Used to specify whether timestamps are enabled or disabled for a DE. + */ +#define SCMI_TELEMETRY_DE_TS_DISABLED 1U /*!< Timestamp disabled */ +#define SCMI_TELEMETRY_DE_TS_ENABLED 2U /*!< Timestamp enabled */ + +/*! + * \brief Response structure for enabled DE list. + * + * Contains the list of enabled Data Events and relevant flags. + */ +struct scmi_telemetry_de_enabled_list_p2a { + int status; /*!< Status of the SCMI request (SCMI_SUCCESS, etc.) */ + uint32_t flags; /*!< Encoded flags indicating DE count information */ + struct mod_telemetry_de_status array[]; /*!< Array of enabled DE statuses */ +}; + +/*! + * \brief SCMI Telemetry Configuration Macros + * + * These macros define the control parameters for configuring + * telemetry settings such as sampling rate and operational modes. + */ + +/*! \brief Bit position and mask for enabling/disabling telemetry */ +#define SCMI_TELEMETRY_CONFIG_CONTROL_EN_POS 0 +#define SCMI_TELEMETRY_CONFIG_CONTROL_EN_MASK \ + (UINT32_C(0x1) << SCMI_TELEMETRY_CONFIG_CONTROL_EN_POS) + +/*! \brief Bit position and mask for configuring telemetry mode */ +#define SCMI_TELEMETRY_CONFIG_CONTROL_MODE_POS 1 +#define SCMI_TELEMETRY_CONFIG_CONTROL_MODE_MASK \ + (UINT32_C(0xF) << SCMI_TELEMETRY_CONFIG_CONTROL_MODE_POS) + +/*! + * \brief Extracts telemetry control mode from configuration flags. + * + * \param[in] CONTROL_VAL The control value containing mode settings. + * + * \return The extracted telemetry control mode. + */ +#define SCMI_TELEMETRY_CONFIG_SET_CONTROL_MODE(CONTROL_VAL) \ + (((CONTROL_VAL) & SCMI_TELEMETRY_CONFIG_CONTROL_MODE_MASK) >> \ + SCMI_TELEMETRY_CONFIG_CONTROL_MODE_POS) + +/*! + * \brief Constructs telemetry control settings. + * + * \param[in] MODE Telemetry mode to configure. + * \param[in] EN Enable (1) or disable (0) telemetry. + * + * \return Encoded control value for telemetry settings. + */ +#define SCMI_TELEMETRY_CONFIG_SET_CONTROL_FLAGS(MODE, EN) \ + ((((MODE) << SCMI_TELEMETRY_CONFIG_CONTROL_MODE_POS) & \ + SCMI_TELEMETRY_CONFIG_CONTROL_MODE_MASK) | \ + (((EN) << SCMI_TELEMETRY_CONFIG_CONTROL_EN_POS) & \ + SCMI_TELEMETRY_CONFIG_CONTROL_EN_MASK)) + +/*! + * \brief Macros for setting telemetry sampling rate. + * + * Defines bit positions and masks for configuring the telemetry sampling rate. + */ + +/*! \brief Bit position and mask for specifying sampling rate in seconds */ +#define SCMI_TELEMETRY_SAMPLING_RATE_SEC_POS 5 +#define SCMI_TELEMETRY_SAMPLING_RATE_SEC_MASK \ + (UINT32_C(0xFFFF) << SCMI_TELEMETRY_SAMPLING_RATE_SEC_POS) + +/*! \brief Bit position and mask for exponent in sampling rate */ +#define SCMI_TELEMETRY_SAMPLING_RATE_EXP_POS 0 +/*! + * \brief Max for exponent in sampling rate + * \note Since exponent can be a negative value, left shift or right shift + * using field position can not be done as shift on some compilers + * are not defined + */ +#define SCMI_TELEMETRY_SAMPLING_RATE_EXP_MASK (UINT32_C(0x1F)) + +/*! + * \brief Constructs the telemetry sampling rate value. + * + * \param[in] SEC Sampling rate in seconds. + * \param[in] EXP Exponent for scaling the sampling rate. + * + * \return Encoded sampling rate value. + */ +#define SCMI_TELEMETRY_SAMPLING_RATE(SEC, EXP) \ + ((((SEC) << SCMI_TELEMETRY_SAMPLING_RATE_SEC_POS) & \ + SCMI_TELEMETRY_SAMPLING_RATE_SEC_MASK) | \ + (((EXP)) & SCMI_TELEMETRY_SAMPLING_RATE_EXP_MASK)) + +/*! + * \brief Enumeration for telemetry configuration control modes. + * + * Defines the possible operation modes for telemetry data collection. + */ +enum scmi_telemetry_config_control_modes { + SCMI_TELEMETRY_CONFIG_CONTROL_MODE_SHMTI = 0, /*!< Use SHMTI */ + SCMI_TELEMETRY_CONFIG_CONTROL_MODE_NOTIFICATIONS = + 1, /*!< Use notifications */ + SCMI_TELEMETRY_CONFIG_CONTROL_MODE_ASYNC_READ = 2, /*!< Use async read */ +}; + +/*! + * \brief Request structure for telemetry configuration settings. + * + * This structure is used in SCMI requests to set telemetry configuration. + */ +struct scmi_telemetry_config_set_a2p { + uint32_t control; /*!< Encoded control flags (mode, enable/disable) */ + uint32_t sampling_rate; /*!< Encoded sampling rate value */ +}; + +/*! + * \brief Response structure for telemetry configuration settings. + * + * This structure is used in SCMI responses to confirm telemetry settings. + */ +struct scmi_telemetry_config_set_p2a { + int32_t status; /*!< Status of the request (SCMI_SUCCESS, etc.) */ +}; + +/*! + * \brief Response structure for retrieving telemetry configuration. + * + * This structure is used in SCMI responses to fetch the current + * telemetry configuration settings. + */ +struct scmi_telemetry_config_get_p2a { + int32_t status; /*!< Status of the request */ + uint32_t control; /*!< Current control settings */ + uint32_t sampling_rate; /*!< Current sampling rate settings */ +}; + +/*! + * \} + */ + +/*! + * \} + */ + +#endif /* INTERNAL_SCMI_TELEMETRY_H */ diff --git a/module/scmi_telemetry/include/mod_scmi_telemetry.h b/module/scmi_telemetry/include/mod_scmi_telemetry.h new file mode 100644 index 0000000000000000000000000000000000000000..2c062a0b03e4e0e5a994663f31e9538beb591d5f --- /dev/null +++ b/module/scmi_telemetry/include/mod_scmi_telemetry.h @@ -0,0 +1,145 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * SCMI Telemetry Protocol Support. + */ + +#ifndef MOD_SCMI_TELEMETRY_H +#define MOD_SCMI_TELEMETRY_H + +#include + +#include + +#include +#include + +/*! + * \ingroup GroupModules + * \defgroup GroupSCMI_TELEMETRY SCMI Telemetry Management Protocol + * \{ + */ + +/*! + * \brief Permission flags governing the ability to use certain SCMI commands + * to interact with a telemetry device. + */ + +/*! No permissions (at least one must be granted) */ +#define MOD_SCMI_TELEMETRY_PERM_INVALID 0UL + +/*! The telemetry device's attributes can be queried */ +#define MOD_SCMI_TELEMETRY_PERM_ATTRIBUTES (1U << 0) + +/*! The permission to access telemetry data */ +#define MOD_SCMI_TELEMETRY_PERM_TELEMETRY (1U << 1) + +/*! + * \brief Telemetry device structure. + * + * \details This structure is used in per-agent telemetry device tables. + * Each device contains an identifier for an element that implements the + * telemetry API. + */ +struct mod_scmi_telemetry_device { + /*! Telemetry element identifier */ + fwk_id_t telemetry_source_id; + + /*! Permissions mask (defined by telemetry device configuration) */ + uint8_t permissions; +}; + +/*! + * \brief SCMI Agent descriptor. + * + * \details Describes an SCMI agent using the telemetry protocol. + * It provides a list of accessible telemetry devices. + */ +struct mod_scmi_telemetry_agent { + /*! Pointer to telemetry device table for this agent */ + const struct mod_scmi_telemetry_device *device_table; + + /*! Number of devices in the agent's telemetry table */ + uint8_t agent_device_count; +}; + +/*! + * \brief SCMI Telemetry module configuration. + */ +struct mod_scmi_telemetry_config { + /*! + * \brief Pointer to agent descriptors table. + * Each entry provides a per-agent view of telemetry devices. + */ + const struct mod_scmi_telemetry_agent *agent_table; + + /*! Number of agents in the system */ + uint32_t agent_count; + + /*! Attributes supported by SCMI telemetry protocol */ + uint32_t attributes; +}; + +/*! + * \brief SCMI Telemetry API indices. + */ +enum scmi_telemetry_api_idx { + /*! Index for the SCMI protocol API */ + MOD_SCMI_TELEMETRY_PROTOCOL_API, + + /*! Number of APIs */ + MOD_SCMI_TELEMETRY_API_COUNT +}; + +/*! + * \defgroup GroupScmiTelemetryPolicyHandler SCMI Telemetry Policy Handler + * \brief Policy handlers for SCMI Telemetry. + * + * \details SCMI policy handlers allow platforms to enforce specific policies. + * These handlers may be overridden in platform-specific implementations. + * + * \{ + */ + +/*! + * \brief Policy handler return values. + * + * \details These values determine whether the SCMI message handler should + * proceed with processing or reject the request. + */ +enum mod_scmi_telemetry_policy_status { + /*! Reject the request */ + MOD_SCMI_TELEMETRY_SKIP_MESSAGE_HANDLER, + + /*! Process the request */ + MOD_SCMI_TELEMETRY_EXECUTE_MESSAGE_HANDLER, +}; + +/*! + * \brief SCMI Telemetry Request Policy. + * + * \details This function determines whether the telemetry request should be + * granted or rejected. The policy handler is executed before message + * processing. + * + * \param[out] policy_status Resulting policy status. + * \param[in] agent_id Identifier of the requesting SCMI agent. + * \param[in] device_id Identifier of the telemetry device. + * + * \retval FWK_SUCCESS Operation succeeded. + * \return Other FWK_* error codes. + */ +int scmi_telemetry_telemetry_request_policy( + enum mod_scmi_telemetry_policy_status *policy_status, + uint32_t agent_id, + uint32_t device_id); + +/*! + * \} + */ + +#endif /* MOD_SCMI_TELEMETRY_H */ diff --git a/module/scmi_telemetry/src/mod_scmi_telemetry.c b/module/scmi_telemetry/src/mod_scmi_telemetry.c new file mode 100644 index 0000000000000000000000000000000000000000..c258e954002ab38a4d839fbe4cfa368d8db2ee96 --- /dev/null +++ b/module/scmi_telemetry/src/mod_scmi_telemetry.c @@ -0,0 +1,1548 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * SCMI Telemetry management protocol support. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef BUILD_HAS_MOD_RESOURCE_PERMS +# include +#endif + +/*! + * \brief SCMI Telemetry context structure. + * + * This structure holds the context for SCMI telemetry, including configuration, + * APIs, and various operational parameters. + */ +struct scmi_telemetry_context { + /*! SCMI Telemetry Configuration */ + const struct mod_scmi_telemetry_config *config; + + /*! Pointer to the bound SCMI protocol API */ + const struct mod_scmi_from_protocol_api *scmi_api; + + /*! Pointer to the telemetry protocol support API */ + const struct mod_telemetry_protocol_support_api *telemetry_api; + + /*! Flag to indicate if telemetry is enabled */ + bool telemetry_enable; + + /*! Current telemetry sampling rate */ + uint32_t current_sampling_rate; + + /*! Pointer to the table storing telemetry agents */ + struct mod_scmi_telemetry_agent *agent_table; + +#ifdef BUILD_HAS_SCMI_NOTIFICATIONS + /*! SCMI notification ID */ + fwk_id_t notification_id; + + /*! Pointer to the SCMI notification API */ + const struct mod_scmi_notification_api *scmi_notification_api; +#endif + +#ifdef BUILD_HAS_MOD_RESOURCE_PERMS + /*! Pointer to the SCMI telemetry permissions API */ + const struct mod_scmi_telemetry_permissions_api *perms_api; +#endif +}; + +/*! + * Function prototypes for handling various SCMI telemetry protocol commands. + * Each function processes a specific SCMI message type and responds + * accordingly. + */ +static int protocol_version_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Handles SCMI Protocol Version request */ + +static int negotiate_protocol_version_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Handles SCMI Protocol Version negotiation */ + +static int protocol_attributes_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Handles SCMI Protocol Attributes request */ + +static int protocol_message_attributes_handler( + fwk_id_t service_id, + const uint32_t + *payload); /*!< Handles SCMI Protocol Message Attributes request */ + +static int scmi_telemetry_list_shmti_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Handles retrieval of SHMTI list */ + +static int scmi_telemetry_de_description_handler( + fwk_id_t service_id, + const uint32_t + *payload); /*!< Handles retrieval of Data Event (DE) description */ + +static int scmi_telemetry_list_update_intervals_handler( + fwk_id_t service_id, + const uint32_t + *payload); /*!< Handles retrieval of available update intervals */ + +static int scmi_telemetry_de_configure_handler( + fwk_id_t service_id, + const uint32_t + *payload); /*!< Handles configuration of a specific Data Event (DE) */ + +static int scmi_telemetry_de_enabled_list_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Retrieves the list of enabled Data Events */ + +static int scmi_telemetry_config_set_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Handles setting telemetry configuration */ + +static int scmi_telemetry_config_get_handler( + fwk_id_t service_id, + const uint32_t + *payload); /*!< Handles retrieval of current telemetry configuration */ + +#ifdef BUILD_HAS_SCMI_NOTIFICATIONS +static int scmi_telemetry_notify_handler( + fwk_id_t service_id, + const uint32_t *payload); /*!< Handles sending telemetry notifications */ +#endif + +/*! + * Internal variables + * These store context and lookup tables for handling telemetry-related + * messages. + */ + +static struct scmi_telemetry_context + scmi_telemetry_ctx; /*!< Global context for SCMI telemetry */ + +/*! + * Lookup table mapping SCMI message types to their corresponding handlers. + * This allows efficient dispatch of incoming SCMI messages. + */ +static handler_table_t msg_handler_table[] = { + [MOD_SCMI_PROTOCOL_VERSION] = protocol_version_handler, + [MOD_SCMI_PROTOCOL_ATTRIBUTES] = protocol_attributes_handler, + [MOD_SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = + protocol_message_attributes_handler, + [MOD_SCMI_TELEMETRY_LIST_SHMTI] = scmi_telemetry_list_shmti_handler, + [MOD_SCMI_TELEMETRY_DE_DESCRIPTION] = scmi_telemetry_de_description_handler, + [MOD_SCMI_TELEMETRY_LIST_UPDATE_INTERVALS] = + scmi_telemetry_list_update_intervals_handler, + [MOD_SCMI_TELEMETRY_DE_CONFIGURE] = scmi_telemetry_de_configure_handler, + [MOD_SCMI_TELEMETRY_DE_ENABLED_LIST] = + scmi_telemetry_de_enabled_list_handler, + [MOD_SCMI_TELEMETRY_CONFIG_SET] = scmi_telemetry_config_set_handler, + [MOD_SCMI_TELEMETRY_CONFIG_GET] = scmi_telemetry_config_get_handler, + [MOD_SCMI_NEGOTIATE_PROTOCOL_VERSION] = negotiate_protocol_version_handler, +}; + +/*! + * Lookup table defining expected payload sizes for each SCMI message type. + * Used to validate incoming SCMI messages. + */ +static size_t payload_size_table[] = { + [MOD_SCMI_PROTOCOL_VERSION] = 0, /*!< No payload for version request */ + [MOD_SCMI_PROTOCOL_ATTRIBUTES] = + 0, /*!< No payload for attributes request */ + [MOD_SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = + (unsigned int)sizeof(struct scmi_protocol_message_attributes_a2p), + [MOD_SCMI_TELEMETRY_LIST_SHMTI] = (unsigned int)sizeof(uint32_t), + [MOD_SCMI_TELEMETRY_DE_DESCRIPTION] = (unsigned int)sizeof(uint32_t), + [MOD_SCMI_TELEMETRY_LIST_UPDATE_INTERVALS] = (unsigned int)sizeof(uint32_t), + [MOD_SCMI_TELEMETRY_DE_CONFIGURE] = + (unsigned int)sizeof(struct scmi_telemetry_de_configure_a2p), + [MOD_SCMI_TELEMETRY_DE_ENABLED_LIST] = (unsigned int)sizeof(uint32_t), + [MOD_SCMI_TELEMETRY_CONFIG_SET] = + (unsigned int)sizeof(struct scmi_telemetry_config_set_a2p), + [MOD_SCMI_TELEMETRY_CONFIG_GET] = + 0, /*!< No payload for telemetry config get request */ + [MOD_SCMI_NEGOTIATE_PROTOCOL_VERSION] = (unsigned int)sizeof( + struct scmi_telemetry_negotiate_protocol_version_a2p), +}; + +/* Ensure the message and payload size tables are consistent */ +static_assert( + FWK_ARRAY_SIZE(msg_handler_table) == FWK_ARRAY_SIZE(payload_size_table), + "[SCMI] telemetry protocol table sizes are not consistent"); + +/*! + * SCMI Telemetry protocol implementation + */ + +static int protocol_version_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + struct scmi_protocol_version_p2a outmsg = { + .status = (int32_t)SCMI_SUCCESS, + .version = SCMI_PROTOCOL_VERSION_TELEMETRY, + }; + + return scmi_telemetry_ctx.scmi_api->respond( + service_id, &outmsg, sizeof(outmsg)); +} + +static int protocol_attributes_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + struct scmi_telemetry_protocol_attributes_p2a outmsg = { + .status = (int32_t)SCMI_SUCCESS, + }; + + int status; + unsigned int agent_id; + + /* Retrieve agent ID associated with the service */ + status = scmi_telemetry_ctx.scmi_api->get_agent_id(service_id, &agent_id); + if (status != FWK_SUCCESS) { + return status; + } + + /* Validate agent ID */ + if (agent_id >= scmi_telemetry_ctx.config->agent_count) { + return FWK_E_PARAM; + } + + /* Retrieve the total number of Data Events (DEs) */ + status = scmi_telemetry_ctx.telemetry_api->get_num_de(&outmsg.num_de); + if (status != FWK_SUCCESS) { + return status; + } + + /* Assign protocol attributes */ + outmsg.attributes = scmi_telemetry_ctx.config->attributes; + + /* Respond to the request */ + return scmi_telemetry_ctx.scmi_api->respond( + service_id, &outmsg, sizeof(outmsg)); +} + +static int protocol_message_attributes_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + struct scmi_protocol_message_attributes_p2a outmsg = { + .status = (int32_t)SCMI_NOT_FOUND, + }; + + if (payload == NULL) { + return FWK_E_PARAM; + } + + size_t outmsg_size = sizeof(outmsg.status); + struct scmi_protocol_message_attributes_a2p params; + + /* Copy payload data */ + params = *(const struct scmi_protocol_message_attributes_a2p *)payload; + + /* Validate message ID and check if a handler exists */ + if ((params.message_id <= MOD_SCMI_NEGOTIATE_PROTOCOL_VERSION) && + (msg_handler_table[params.message_id] != NULL)) { + outmsg.status = (int32_t)SCMI_SUCCESS; + outmsg_size = sizeof(outmsg); + } + + /* Respond with the attributes */ + return scmi_telemetry_ctx.scmi_api->respond( + service_id, &outmsg, outmsg_size); +} + +#ifdef RESOURCE_PERMISSION +/*! + * \brief Retrieves the agent identifier associated with a given service. + * + * @param[in] service_id The SCMI service identifier. + * @param[out] agent_id Pointer to store the retrieved agent ID. + * + * @return FWK_SUCCESS The operation was successful. + * @return FWK_E_PARAM Invalid agent ID or service ID. + */ +static int get_agent_id(fwk_id_t service_id, unsigned int *agent_id) +{ + int status; + + if (agent_id == NULL) { + return FWK_E_PARAM; + } + + status = scmi_telemetry_ctx.scmi_api->get_agent_id(service_id, agent_id); + if (status != FWK_SUCCESS) { + return status; + } + + if (*agent_id >= scmi_telemetry_ctx.config->agent_count) { + return FWK_E_PARAM; + } + + return FWK_SUCCESS; +} + +/* + * \brief Retrieves the agent entry from the agent table based on the service + * ID. + * + * @param[in] service_id The SCMI service identifier. + * @param[out] agent Pointer to store the retrieved agent entry. + * + * @return FWK_SUCCESS The operation was successful. + * @return FWK_E_PARAM Invalid service ID or agent entry. + */ +static int get_agent_entry( + fwk_id_t service_id, + const struct mod_scmi_telemetry_agent **agent) +{ + int status; + unsigned int agent_id; + + if (agent == NULL) { + return FWK_E_PARAM; + } + + status = get_agent_id(service_id, &agent_id); + if (status != FWK_SUCCESS) { + return status; + } + + *agent = &scmi_telemetry_ctx.config->agent_table[agent_id]; + + return FWK_SUCCESS; +} + +/*! + * \brief Handles the request policy for SCMI telemetry. + * + * This function defines the default policy behavior for handling telemetry + * requests. It sets the policy status to execute the message handler. + * + * @param[out] policy_status The policy status to be executed. + * @param[out] mode Pointer to store the telemetry mode (optional). + * @param[out] other_params Pointer to store any other param (optional). + * @param[in] agent_id The agent ID requesting the reset. + * @param[in] domain_id The domain ID for which the reset is requested. + * + * @return FWK_SUCCESS The operation was successful. + */ +FWK_WEAK int scmi_telemetry_reset_request_policy( + enum mod_scmi_telemetry_policy_status *policy_status, + enum mod_telemetry_mode *mode, + uint32_t *other_params, + uint32_t agent_id, + uint32_t domain_id) +{ + if (policy_status == NULL) { + return FWK_E_PARAM; + } + + *policy_status = MOD_SCMI_TELEMETRY_EXECUTE_MESSAGE_HANDLER; + + return FWK_SUCCESS; +} +#endif + +/*! + * \brief Determines the maximum number of objects that can fit in a payload. + * + * This function calculates how many objects can be included in a single SCMI + * telemetry response payload, given the maximum payload size. + * + * @param[in] service_id SCMI service identifier. + * @param[in] header_size Size of the response header. + * @param[in] object_size Size of each individual object. + * @param[in, out] remain_count Pointer to the remaining number of objects. + * Updated to reflect the number of objects left after processing. + * @param[out] total_count Pointer to store the computed number of objects + * that can be included in the response payload. + * + * @return FWK_SUCCESS If the operation is successful. + * @return FWK_E_RANGE If there are no remaining objects to process. + * @return FWK_E_SIZE If the payload size is too small to fit any objects. + */ +static int max_objects_in_payload( + fwk_id_t service_id, + size_t header_size, + size_t object_size, + uint32_t *remain_count, + uint32_t *total_count) +{ + int status; + size_t max_payload_size; + uint32_t total_remaining = 0; + uint32_t count = 0; + + /* Ensure valid output parameters */ + if (remain_count == NULL || total_count == NULL || object_size == 0) { + return FWK_E_PARAM; + } + + *total_count = 0; + total_remaining = *remain_count; + + /* Check if there are objects left to process */ + if (total_remaining == 0) { + return FWK_E_RANGE; + } + + /* + * Get the maximum payload size to determine how many entries can + * be returned in one response. + */ + status = scmi_telemetry_ctx.scmi_api->get_max_payload_size( + service_id, &max_payload_size); + if (status != FWK_SUCCESS) { + return status; + } + + /* Ensure payload can accommodate at least the header */ + if (max_payload_size < header_size) { + return FWK_E_SIZE; + } + + max_payload_size -= header_size; + count = max_payload_size / object_size; + + /* Ensure count does not exceed remaining objects */ + count = (uint32_t)FWK_MIN(count, total_remaining); + + /* If count is zero, the payload size is too small */ + if (count == 0) { + return FWK_E_SIZE; + } + + /* Update the remaining count and total count */ + *remain_count = total_remaining - count; + *total_count = count; + + return FWK_SUCCESS; +} + +/*! + * \brief Handles retrieval of SHMTI list for SCMI Telemetry. + * + * This function processes the request to retrieve SHMTI descriptors available + * in the telemetry system. It ensures correct indexing, payload handling, and + * response formatting. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload containing the index. + * + * @return FWK_SUCCESS The operation was successful. + * @return SCMI_OUT_OF_RANGE If the requested index is out of range. + * @return FWK_E_PARAM If an invalid parameter is provided. + */ +static int scmi_telemetry_list_shmti_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + int status; + size_t i; + uint32_t index; + uint32_t num_shmti; + struct mod_telemetry_shmti_desc shmti_desc; + uint32_t count; + uint32_t remain_count; + int respond_status; + + struct scmi_telemetry_list_shmti_p2a return_values = { + .status = SCMI_GENERIC_ERROR + }; + + uint32_t payload_size = sizeof(return_values); + + /* Validate payload pointer */ + if (payload == NULL) { + return FWK_E_PARAM; + } + + index = *payload; + + /* Retrieve the total number of SHMTI regions */ + status = scmi_telemetry_ctx.telemetry_api->get_num_shmti(&num_shmti); + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Validate the requested index */ + if (index >= num_shmti) { + return_values.status = SCMI_NOT_FOUND; + goto exit; + } + + remain_count = num_shmti - index; + + /* Determine the maximum number of entries that can fit in the response + * payload */ + status = max_objects_in_payload( + service_id, + sizeof(struct scmi_telemetry_list_shmti_p2a), + sizeof(struct mod_telemetry_shmti_desc), + &remain_count, + &count); + + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Iterate through the SHMTI entries and add them to the response */ + for (i = 0; i < count; i++, index++) { + status = + scmi_telemetry_ctx.telemetry_api->get_shmti(index, &shmti_desc); + if (status != FWK_SUCCESS) { + goto exit; + } + + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, payload_size, &shmti_desc, sizeof(shmti_desc)); + if (status != FWK_SUCCESS) { + goto exit; + } + + payload_size += sizeof(shmti_desc); + } + + return_values.status = SCMI_SUCCESS; + return_values.num_shmti = + SCMI_TELEMETRY_LIST_SHMTI_TOTAL_SHMTI(remain_count, count); + + /* Write the final response data */ + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, 0, &return_values, sizeof(return_values)); + +exit: + /* Send response, handling both success and error cases */ + respond_status = scmi_telemetry_ctx.scmi_api->respond( + service_id, + (return_values.status == SCMI_SUCCESS) ? NULL : &return_values.status, + (return_values.status == SCMI_SUCCESS) ? payload_size : + sizeof(return_values.status)); + + if (respond_status != FWK_SUCCESS) { + FWK_LOG_DEBUG( + "[SCMI-TELEMETRY] Failed response in %s @%d", __func__, __LINE__); + return respond_status; + } + + return status; +} + +/*! + * \brief Handles retrieval of Data Event (DE) descriptions for SCMI Telemetry. + * + * This function processes a request to retrieve descriptions of telemetry + * Data Events (DEs). It ensures proper indexing, payload handling, and response + * formatting. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload containing the index. + * + * @return FWK_SUCCESS The operation was successful. + * @return SCMI_OUT_OF_RANGE If the requested index is out of range. + * @return FWK_E_PARAM If an invalid parameter is provided. + */ +static int scmi_telemetry_de_description_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + size_t i; + uint32_t num_de; + uint32_t de_desc_index; + uint32_t count, remain_count; + struct mod_telemetry_de_desc de_desc; + struct scmi_telemetry_de_desc_p2a return_values = { + .status = SCMI_GENERIC_ERROR + }; + + uint32_t payload_size = sizeof(return_values); + int status = FWK_SUCCESS; + int respond_status; + + /* Validate payload pointer */ + if (payload == NULL) { + return FWK_E_PARAM; + } + + /* Extract Data Event description index */ + de_desc_index = *(const uint32_t *)payload; + + /* Retrieve total number of Data Events */ + status = scmi_telemetry_ctx.telemetry_api->get_num_de(&num_de); + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Validate the requested index */ + if (de_desc_index >= num_de) { + return_values.status = SCMI_NOT_FOUND; + goto exit; + } + + remain_count = num_de - de_desc_index; + + /* Determine the maximum number of entries that can fit in the response + * payload */ + status = max_objects_in_payload( + service_id, + sizeof(struct scmi_telemetry_de_desc_p2a), + sizeof(struct mod_telemetry_de_desc), + &remain_count, + &count); + + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Iterate through the DE descriptors and add them to the response */ + for (i = 0; i < count; i++, de_desc_index++) { + status = + scmi_telemetry_ctx.telemetry_api->get_de(de_desc_index, &de_desc); + if (status != FWK_SUCCESS) { + goto exit; + } + + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, payload_size, &de_desc, sizeof(de_desc)); + if (status != FWK_SUCCESS) { + goto exit; + } + + payload_size += sizeof(de_desc); + } + + /* Populate response values */ + return_values.num_desc = SCMI_TELEMETRY_DE_DESC_TOTAL(remain_count, count); + return_values.status = SCMI_SUCCESS; + + /* Write the final response data */ + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, 0, &return_values, sizeof(return_values)); + +exit: + /* Send response, handling both success and error cases */ + respond_status = scmi_telemetry_ctx.scmi_api->respond( + service_id, + (return_values.status == SCMI_SUCCESS) ? NULL : &return_values.status, + (return_values.status == SCMI_SUCCESS) ? payload_size : + sizeof(return_values.status)); + + if (respond_status != FWK_SUCCESS) { + FWK_LOG_DEBUG( + "[SCMI-TELEMETRY] Response failed in %s @%d", __func__, __LINE__); + return respond_status; + } + + return status; +} + +/*! + * \brief Encodes an update interval in SCMI telemetry format. + * + * This function encodes a telemetry sampling interval (e.g. in milliseconds) + * into the SCMI-defined format for update intervals. The encoded interval + * consists of: + * - A number of seconds (left-shifted into its field position), + * - An exponent value (bit-masked into its field). + * + * The format complies with the SCMI specification for telemetry update + * intervals. + * + * \param[in] seconds_base Sampling interval e.g. in milliseconds. + * \param[in] exponent Exponent value (base-10), typically negative (e.g., -3). + * This determines the resolution of the interval. + * + * \retval Encoded interval value combining seconds and exponent. + * \retval 0 If the seconds value exceeds the allowed bit field range. + */ +static uint32_t encode_interval(uint32_t seconds_base, int8_t exponent) +{ + uint32_t seconds_field; + uint32_t exponent_field; + + /* Shift seconds to proper bit position */ + seconds_field = seconds_base << MOD_TELEMETRY_INTERVAL_SECONDS_POS; + + /* Validate seconds field fits within defined mask */ + if (seconds_field & ~(MOD_TELEMETRY_INTERVAL_NUM_SECONDS_MASK)) { + return 0; /* Indicate error */ + } + + /* + * Cast exponent to unsigned and apply bitmask. + * Assumes two's complement representation. + */ + exponent_field = + ((uint32_t)exponent) & MOD_TELEMETRY_INTERVAL_NUM_EXPONENT_MASK; + + /* Combine the shifted seconds and masked exponent */ + return seconds_field | exponent_field; +} + +/*! + * \brief Handles retrieval of available update intervals for SCMI Telemetry. + * + * This function processes a request to retrieve a list of available update + * intervals for telemetry data refresh. It ensures correct indexing, payload + * handling, and response formatting. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload containing the index. + * + * @return FWK_SUCCESS The operation was successful. + * @return SCMI_OUT_OF_RANGE If the requested index is out of range. + * @return FWK_E_PARAM If an invalid parameter is provided. + */ +static int scmi_telemetry_list_update_intervals_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + size_t i; + uint32_t num_intervals; + /* Index received from the agent as part of the payload */ + uint32_t index, count, remain_count; + + uint32_t sampling_rate; + uint32_t interval; + enum mod_telemetry_update_interval_formats interval_format; + + struct scmi_telemetry_list_update_intervals_p2a return_values = { + .status = SCMI_GENERIC_ERROR + }; + + uint32_t payload_size = sizeof(return_values); + int status = FWK_SUCCESS; + int respond_status; + + /* Validate payload pointer */ + if (payload == NULL) { + return FWK_E_PARAM; + } + + /* Extract index from the payload */ + index = *payload; + + /* Retrieve available update interval information */ + status = scmi_telemetry_ctx.telemetry_api->get_update_intervals_info( + &num_intervals, &interval_format); + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Validate the requested index */ + if (index >= num_intervals) { + return_values.status = SCMI_NOT_FOUND; + goto exit; + } + + remain_count = num_intervals - index; + + /*! + * Determine the maximum number of entries that can fit in the response + * payload + */ + status = max_objects_in_payload( + service_id, + sizeof(struct scmi_telemetry_list_update_intervals_p2a), + sizeof(uint32_t), + &remain_count, + &count); + if (status != FWK_SUCCESS) { + goto exit; + } + + /*! + * Iterate through the available update intervals and add them to the + * response + */ + for (i = 0; i < count; i++, index++) { + status = scmi_telemetry_ctx.telemetry_api->get_update_interval( + index, &sampling_rate); + + if (status != FWK_SUCCESS) { + goto exit; + }; + + interval = encode_interval(sampling_rate, -3); + + if (interval == 0) { + return_values.status = SCMI_OUT_OF_RANGE; + goto exit; + } + + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, payload_size, &interval, sizeof(interval)); + if (status != FWK_SUCCESS) { + goto exit; + } + payload_size += sizeof(interval); + } + + /* Populate response values */ + return_values.status = (int32_t)SCMI_SUCCESS; + return_values.flags = SCMI_TELEMETRY_UPDATE_INTERVALS_FLAG( + remain_count, interval_format, count); + + /* Write the final response data */ + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, 0, &return_values, sizeof(return_values)); + +exit: + /* Send response, handling both success and error cases */ + respond_status = scmi_telemetry_ctx.scmi_api->respond( + service_id, + (return_values.status == SCMI_SUCCESS) ? NULL : &return_values.status, + (return_values.status == SCMI_SUCCESS) ? payload_size : + sizeof(return_values.status)); + + if (respond_status != FWK_SUCCESS) { + FWK_LOG_DEBUG( + "[SCMI-TELEMETRY] Response failed in %s @%d", __func__, __LINE__); + return respond_status; + } + + return status; +} + +/*! + * \brief Handles the configuration of a specific Data Event (DE) for SCMI + * Telemetry. + * + * This function processes a request to enable or disable a telemetry Data Event + * (DE). It ensures proper validation of the DE ID and flags, applies the + * required configuration, and formats the response accordingly. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload containing DE + * configuration. + * + * @return FWK_SUCCESS The operation was successful. + * @return SCMI_INVALID_PARAMETERS If invalid flags or DE ID are provided. + * @return FWK_E_PARAM If an invalid parameter is detected. + */ +static int scmi_telemetry_de_configure_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + int status; + int respond_status; + uint32_t de_id; + uint32_t flags; + uint32_t response_size; + + struct scmi_telemetry_de_configure_a2p *params = NULL; + struct scmi_telemetry_de_configure_p2a return_values = { + .status = SCMI_GENERIC_ERROR, + .shmti_id = SCMI_TELEMETRY_DE_SHMTI_ID_NOT_SUPPORTED, + .shmti_de_offset = SCMI_TELEMETRY_DE_SHMTI_ID_OFFSET_NOT_SUPPORTED, + }; + + /* Validate payload pointer */ + if (payload == NULL) { + return FWK_E_PARAM; + } + + /* Parse request parameters */ + params = (struct scmi_telemetry_de_configure_a2p *)payload; + + de_id = params->de_id; + flags = params->flags; + + /* Check if all DEs should be disabled */ + if (SCMI_TELEMETRY_ALL_DE_DISABLED(flags)) { + if (SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE(flags) != 0) { + status = FWK_E_PARAM; + return_values.status = SCMI_INVALID_PARAMETERS; + goto exit; + } + + status = scmi_telemetry_ctx.telemetry_api->disable_all_de(); + return_values.status = + (status == FWK_SUCCESS) ? SCMI_SUCCESS : SCMI_GENERIC_ERROR; + goto exit; + } + + /* Process DE configuration mode */ + switch (SCMI_TELEMETRY_DE_CONFIGURE_DE_MODE(flags)) { + case SCMI_TELEMETRY_DE_DISABLE: + status = scmi_telemetry_ctx.telemetry_api->disable_de(de_id); + return_values.status = + (status == FWK_SUCCESS) ? SCMI_SUCCESS : SCMI_GENERIC_ERROR; + break; + case SCMI_TELEMETRY_DE_ENABLE_NON_TS: + status = scmi_telemetry_ctx.telemetry_api->enable_de_non_ts(de_id); + return_values.status = + (status == FWK_SUCCESS) ? SCMI_SUCCESS : SCMI_GENERIC_ERROR; + break; + case SCMI_TELEMETRY_DE_ENABLE_TS: + status = scmi_telemetry_ctx.telemetry_api->enable_de_ts(de_id); + return_values.status = + (status == FWK_SUCCESS) ? SCMI_SUCCESS : SCMI_GENERIC_ERROR; + break; + default: + status = FWK_E_PARAM; + return_values.status = SCMI_INVALID_PARAMETERS; + break; + } + +exit: + /* Determine response size */ + response_size = (return_values.status == SCMI_SUCCESS) ? + sizeof(return_values) : + sizeof(return_values.status); + + /* Send response */ + respond_status = scmi_telemetry_ctx.scmi_api->respond( + service_id, &return_values, response_size); + + /* Log response failure, if any */ + if (respond_status != FWK_SUCCESS) { + FWK_LOG_DEBUG( + "[SCMI-TELEMETRY] Response failed in %s @%d", __func__, __LINE__); + return respond_status; + } + + return status; +} + +/*! + * \brief Retrieves the list of enabled Data Events (DEs) for SCMI Telemetry. + * + * This function processes a request to fetch the list of currently enabled DEs. + * It ensures proper indexing, payload handling, and response formatting. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload containing the index. + * + * @return FWK_SUCCESS The operation was successful. + * @return SCMI_OUT_OF_RANGE If the requested index is out of range. + * @return FWK_E_PARAM If an invalid parameter is provided. + */ +static int scmi_telemetry_de_enabled_list_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + size_t i; + uint32_t num_de_enabled; + uint32_t index, count, remain_count; + struct mod_telemetry_de_status de_status; + struct scmi_telemetry_de_enabled_list_p2a return_values = { + .status = SCMI_GENERIC_ERROR + }; + + uint32_t de_enabled_value[2]; + + uint32_t payload_size = sizeof(return_values); + int status = FWK_SUCCESS; + int respond_status; + + /* Validate payload pointer */ + if (payload == NULL) { + return FWK_E_PARAM; + } + + /* Get index from parameter */ + index = *payload; + + /* Retrieve the number of currently enabled DEs */ + status = + scmi_telemetry_ctx.telemetry_api->get_num_de_enabled(&num_de_enabled); + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Validate the requested index */ + if (index >= num_de_enabled) { + return_values.status = SCMI_NOT_FOUND; + goto exit; + } + + remain_count = num_de_enabled - index; + + /*! + * Determine the maximum number of entries that can fit in the response + * payload + */ + status = max_objects_in_payload( + service_id, + sizeof(struct scmi_telemetry_de_enabled_list_p2a), + sizeof(de_enabled_value), + &remain_count, + &count); + if (status != FWK_SUCCESS) { + goto exit; + } + + /* Retrieve the list of enabled DEs */ + for (i = 0; i < count; i++, index++) { + status = + scmi_telemetry_ctx.telemetry_api->get_de_enabled(index, &de_status); + if (status != FWK_SUCCESS) { + goto exit; + } + de_enabled_value[0] = de_status.de_id; + de_enabled_value[1] = de_status.de_ts_mode; + + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, + payload_size, + &de_enabled_value[0], + sizeof(de_enabled_value)); + if (status != FWK_SUCCESS) { + goto exit; + } + payload_size += sizeof(de_enabled_value); + } + + /* Populate response values */ + return_values.status = (int32_t)SCMI_SUCCESS; + return_values.flags = + SCMI_TELEMETRY_DE_ENABLED_LIST_FLAG(remain_count, count); + + /* Write the final response data */ + status = scmi_telemetry_ctx.scmi_api->write_payload( + service_id, 0, &return_values, sizeof(return_values)); + +exit: + /* Send response, handling both success and error cases */ + respond_status = scmi_telemetry_ctx.scmi_api->respond( + service_id, + (return_values.status == SCMI_SUCCESS) ? NULL : &return_values.status, + (return_values.status == SCMI_SUCCESS) ? payload_size : + sizeof(return_values.status)); + + if (respond_status != FWK_SUCCESS) { + FWK_LOG_DEBUG( + "[SCMI-TELEMETRY] Response failed in %s @%d", __func__, __LINE__); + return respond_status; + } + + return status; +} + +/*! + * \brief Retrieves the multiplier for a given sampling rate. + * + * This function extracts the exponent from the sampling rate and adjusts it + * for conversion. The exponent is extracted using the + * `MOD_TELEMETRY_INTERVAL_EXPONENT` macro and then incremented by 7 to + * account for the `sec * 10^7` conversion. + * + * @param[in] sampling_rate The raw sampling rate value from SCMI. + * + * @return The computed multiplier for converting seconds. + */ +static uint64_t get_sec_multiplier(uint32_t sampling_rate) +{ + struct mod_telemetry_update_interval_exponent exponent; + int32_t val; + + /*! + * Extract and sign-extend the exponent from the sampling rate + * Sign-extend happens automatically due to exponent.value is an + * integer type. + */ + exponent.value = MOD_TELEMETRY_INTERVAL_EXPONENT(sampling_rate); + + val = exponent.value; + + /* + * Adjust the exponent, so that resulting value remain >= 0 + * Note: Extra variable 'var' is required because + * width(5 bits) of exponent.value may not sufficient + * if following operation is done directly on exponent.value + */ + val += 7; + + /* Compute the multiplier using power-of-10 */ + return (uint64_t)__builtin_powi(10, val); +} + +/*! + * \brief Converts a raw SCMI sampling rate to milliseconds. + * + * This function extracts the base seconds component and computes the + * milliseconds equivalent using a multiplier derived from the exponent. + * + * @param[in] sampling_rate The raw sampling rate value from SCMI. + * + * @return The sampling rate in milliseconds. + */ +uint64_t convert_sampling_rate_to_msecs(uint32_t sampling_rate) +{ + uint32_t seconds; + uint64_t sec_multiplier; + + /* Get the multiplier */ + sec_multiplier = get_sec_multiplier(sampling_rate); + + /* Extract the seconds component from the sampling rate */ + seconds = MOD_TELEMETRY_INTERVAL_SECONDS(sampling_rate); + + /* Compute and return the final value in milliseconds + * Since sec_multiplier is adjusted by 10^7 for msec + * conversion divide it by 10^4 effectivly multiply + * by 10^3. + */ + return (seconds * sec_multiplier) / 10000; +} + +/*! + * \brief Handles setting telemetry configuration for SCMI Telemetry. + * + * This function processes a request to enable or disable telemetry, + * sets the sampling rate, and validates the configuration mode. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload containing configuration + * parameters. + * + * @return FWK_SUCCESS The operation was successful. + * @return SCMI_INVALID_PARAMETERS If an invalid control mode is provided. + * @return SCMI_PROTOCOL_ERROR If enabling/disabling telemetry fails. + */ +static int scmi_telemetry_config_set_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + int status; + int respond_status; + uint32_t response_size; + uint64_t sampling_rate_msec; + + struct scmi_telemetry_config_set_a2p *params = NULL; + struct scmi_telemetry_config_set_p2a return_values = { + .status = SCMI_GENERIC_ERROR, + }; + + /* Validate payload pointer */ + if (payload == NULL) { + return FWK_E_PARAM; + } + + /* Parse request parameters */ + params = (struct scmi_telemetry_config_set_a2p *)payload; + + /* Check if telemetry should be disabled */ + if ((SCMI_TELEMETRY_CONFIG_CONTROL_EN_MASK & params->control) == 0) { + status = scmi_telemetry_ctx.telemetry_api->telemetry_disable(); + if (status != FWK_SUCCESS) { + return_values.status = SCMI_PROTOCOL_ERROR; + } else { + scmi_telemetry_ctx.telemetry_enable = false; + return_values.status = SCMI_SUCCESS; + } + goto exit; + } + + if (SCMI_TELEMETRY_CONFIG_SET_CONTROL_MODE(params->control) != + SCMI_TELEMETRY_CONFIG_CONTROL_MODE_SHMTI) { + return_values.status = SCMI_NOT_SUPPORTED; + status = FWK_E_PARAM; + goto exit; + } + + /* Enable telemetry */ + status = scmi_telemetry_ctx.telemetry_api->telemetry_enable(); + if (status != FWK_SUCCESS) { + return_values.status = SCMI_PROTOCOL_ERROR; + goto exit; + } + + scmi_telemetry_ctx.telemetry_enable = true; + + sampling_rate_msec = convert_sampling_rate_to_msecs(params->sampling_rate); + status = scmi_telemetry_ctx.telemetry_api->set_sampling_rate( + (uint32_t)sampling_rate_msec); + if (status != FWK_SUCCESS) { + return_values.status = SCMI_PROTOCOL_ERROR; + goto exit; + } + scmi_telemetry_ctx.current_sampling_rate = params->sampling_rate; + +exit: + /* Determine response size */ + response_size = (return_values.status == SCMI_SUCCESS) ? + sizeof(return_values) : + sizeof(return_values.status); + + /* Send response */ + respond_status = scmi_telemetry_ctx.scmi_api->respond( + service_id, &return_values, response_size); + + /* Log response failure */ + if (respond_status != FWK_SUCCESS) { + FWK_LOG_DEBUG( + "[SCMI-TELEMETRY] Response failed in %s @%d", __func__, __LINE__); + return respond_status; + } + + return status; +} + +/*! + * \brief Handles retrieval of current telemetry configuration. + * + * This function processes a request to fetch the current telemetry + * configuration. It returns the current telemetry enable state and the active + * sampling rate. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload (unused in this function). + * + * @return FWK_SUCCESS The operation was successful. + */ +static int scmi_telemetry_config_get_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + int status; + struct scmi_telemetry_config_get_p2a return_values = { + .status = SCMI_SUCCESS, + .control = 0, + .sampling_rate = 0, + }; + + /* Check if telemetry is enabled and set the response accordingly */ + if (scmi_telemetry_ctx.telemetry_enable) { + return_values.control = (1U << SCMI_TELEMETRY_CONFIG_CONTROL_EN_POS); + return_values.sampling_rate = scmi_telemetry_ctx.current_sampling_rate; + } + + /* Send response */ + status = scmi_telemetry_ctx.scmi_api->respond( + service_id, &return_values, sizeof(return_values)); + + return status; +} + +/*! + * \brief Handles the negotiation of SCMI protocol version. + * + * This function is currently not supported and returns `FWK_E_SUPPORT` + * indicating that version negotiation is not implemented. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload (unused). + * + * @return FWK_E_SUPPORT Protocol version negotiation is not supported. + */ +static int negotiate_protocol_version_handler( + fwk_id_t service_id, + const uint32_t *payload) +{ + return FWK_E_SUPPORT; +} + +#ifdef BUILD_HAS_MOD_RESOURCE_PERMS +/*! + * \brief Handles SCMI resource permission checks for telemetry. + * + * This function validates whether a given SCMI message has the required + * permissions before it is processed. It currently returns `FWK_E_SUPPORT` + * indicating that the permission check is not implemented. + * + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload. + * @param[in] payload_size Size of the request payload. + * @param[in] message_id The SCMI message identifier. + * + * @return FWK_E_SUPPORT Resource permission checks are not supported. + */ +static int scmi_telemetry_permissions_handler( + fwk_id_t service_id, + const uint32_t *payload, + size_t payload_size, + unsigned int message_id) +{ + return FWK_E_SUPPORT; +} +#endif + +/*! + * \brief Retrieves the SCMI protocol ID for telemetry. + * + * This function returns the protocol ID associated with SCMI telemetry. + * + * @param[in] protocol_id The framework identifier for the protocol. + * @param[out] scmi_protocol_id Pointer to store the SCMI protocol ID. + * + * @return FWK_SUCCESS Operation completed successfully. + */ +static int scmi_telemetry_get_scmi_protocol_id( + fwk_id_t protocol_id, + uint8_t *scmi_protocol_id) +{ + *scmi_protocol_id = MOD_SCMI_PROTOCOL_ID_TELEMETRY; + + return FWK_SUCCESS; +} + +/*! + * \brief Handles incoming SCMI messages for telemetry. + * + * This function validates incoming SCMI telemetry messages and dispatches them + * to their respective handlers based on the message ID. It also ensures that + * any required resource permissions are checked. + * + * @param[in] protocol_id The framework identifier for the SCMI protocol. + * @param[in] service_id The SCMI service identifier. + * @param[in] payload Pointer to the request payload. + * @param[in] payload_size Size of the request payload. + * @param[in] message_id The SCMI message identifier. + * + * @return FWK_SUCCESS Operation completed successfully. + * @return SCMI_DENIED If the message is denied due to permission restrictions. + * @return SCMI_NOT_SUPPORTED If the message ID is not supported. + */ +static int scmi_telemetry_message_handler( + fwk_id_t protocol_id, + fwk_id_t service_id, + const uint32_t *payload, + size_t payload_size, + unsigned int message_id) +{ + int validation_result; + + /* Validate the SCMI message */ + validation_result = scmi_telemetry_ctx.scmi_api->scmi_message_validation( + MOD_SCMI_PROTOCOL_ID_TELEMETRY, + service_id, + payload, + payload_size, + message_id, + payload_size_table, + (unsigned int)MOD_SCMI_TELEMETRY_COMMAND_COUNT, + msg_handler_table); + +#ifdef BUILD_HAS_MOD_RESOURCE_PERMS + /* Check if the message requires resource permission validation */ + if (message_id >= MOD_SCMI_MESSAGE_ID_ATTRIBUTE) { + if (scmi_telemetry_permissions_handler( + service_id, payload, payload_size, message_id) != FWK_SUCCESS) { + validation_result = SCMI_DENIED; + } + } +#endif + + if (validation_result != SCMI_SUCCESS) { + return scmi_telemetry_ctx.scmi_api->respond( + service_id, &validation_result, sizeof(validation_result)); + } + + /* Dispatch the message to the appropriate handler */ + if (msg_handler_table[message_id] == NULL) { + return FWK_E_PARAM; + } + + return msg_handler_table[message_id](service_id, payload); +} + +/*! + * \brief SCMI telemetry module API structure. + * + * This structure defines the interface for handling SCMI telemetry messages. + */ +static struct mod_scmi_to_protocol_api + scmi_telemetry_mod_scmi_to_protocol_api = { + .get_scmi_protocol_id = scmi_telemetry_get_scmi_protocol_id, + .message_handler = scmi_telemetry_message_handler + }; + +/* + * Framework handlers + */ + +/*! + * \brief Initializes the SCMI telemetry module. + * + * This function initializes the SCMI telemetry module by storing the provided + * configuration data. It ensures that the configuration and agent table are + * valid. + * + * @param[in] module_id The module identifier. + * @param[in] element_count Number of elements in the module (unused). + * @param[in] data Pointer to the module configuration. + * + * @return FWK_SUCCESS Initialization was successful. + * @return FWK_E_PARAM If the configuration data is NULL or the agent table is + * NULL. + */ +static int scmi_telemetry_init( + fwk_id_t module_id, + unsigned int element_count, + const void *data) +{ + const struct mod_scmi_telemetry_config *config; + + if (data == NULL) { + return FWK_E_PARAM; + } + + config = (const struct mod_scmi_telemetry_config *)data; + + if (config->agent_table == NULL) { + return FWK_E_PARAM; + } + + scmi_telemetry_ctx.config = config; + + return FWK_SUCCESS; +} + +#ifdef BUILD_HAS_SCMI_NOTIFICATIONS +/*! + * \brief Initializes SCMI telemetry notifications. + * + * This function is currently not implemented and triggers an assertion failure + * when called. + * + * @return No return, function triggers an assertion failure. + */ +static int scmi_telemetry_init_notifications(void) +{ + fwk_assert(false); +} +#endif + +/*! + * \brief Binds required module dependencies for SCMI telemetry. + * + * This function binds the SCMI protocol API and, if enabled, binds + * the SCMI notification API and telemetry API. + * + * @param[in] id The module identifier. + * @param[in] round The binding round (ensures dependencies are bound in order). + * + * @return FWK_SUCCESS The binding was successful. + * @return FWK_E_PANIC If any of the required bindings fail. + */ +static int scmi_telemetry_bind(fwk_id_t id, unsigned int round) +{ + int status; + + /* Perform binding only in the first round */ + if (round == 1) { + return FWK_SUCCESS; + } + + /* Bind the SCMI protocol API */ + status = fwk_module_bind( + FWK_ID_MODULE(FWK_MODULE_IDX_SCMI), + FWK_ID_API(FWK_MODULE_IDX_SCMI, MOD_SCMI_API_IDX_PROTOCOL), + &scmi_telemetry_ctx.scmi_api); + if (status != FWK_SUCCESS) { + return status; + } + +#ifdef BUILD_HAS_SCMI_NOTIFICATIONS + /* Bind the SCMI notification API */ + status = fwk_module_bind( + FWK_ID_MODULE(FWK_MODULE_IDX_SCMI), + FWK_ID_API(FWK_MODULE_IDX_SCMI, MOD_SCMI_API_IDX_NOTIFICATION), + &scmi_telemetry_ctx.scmi_notification_api); + if (status != FWK_SUCCESS) { + return status; + } +#endif + +#ifdef BUILD_HAS_MOD_TELEMETRY + /* Bind the telemetry protocol API */ + return fwk_module_bind( + FWK_ID_MODULE(FWK_MODULE_IDX_TELEMETRY), + FWK_ID_API(FWK_MODULE_IDX_TELEMETRY, 0), + &scmi_telemetry_ctx.telemetry_api); +#else + return FWK_SUCCESS; +#endif +} + +/*! + * \brief Processes incoming API bind requests. + * + * This function handles bind requests for the SCMI telemetry protocol API. + * + * @param[in] source_id The identifier of the module requesting the API. + * @param[in] target_id The identifier of the module providing the API. + * @param[in] api_id The API identifier. + * @param[out] api Pointer to the requested API. + * + * @return FWK_SUCCESS If the requested API is provided successfully. + * @return FWK_E_ACCESS If the requested API is not available. + */ +static int scmi_telemetry_process_bind_request( + fwk_id_t source_id, + fwk_id_t target_id, + fwk_id_t api_id, + const void **api) +{ + switch ((enum scmi_telemetry_api_idx)fwk_id_get_api_idx(api_id)) { + case MOD_SCMI_TELEMETRY_PROTOCOL_API: + if (api == NULL) { + return FWK_E_PARAM; + } + *api = &scmi_telemetry_mod_scmi_to_protocol_api; + break; + + default: + return FWK_E_ACCESS; + } + + return FWK_SUCCESS; +} + +#if defined(BUILD_HAS_SCMI_NOTIFICATIONS) && defined(BUILD_HAS_NOTIFICATION) +/*! + * \brief Processes received SCMI telemetry notifications. + * + * This function is a stub for handling telemetry notifications. + * + * @param[in] event The received event. + * @param[out] resp_event The response event (if needed). + * + * @return FWK_SUCCESS The function always returns success. + */ +static int scmi_telemetry_process_notification( + const struct fwk_event *event, + struct fwk_event *resp_event) +{ + return FWK_SUCCESS; +} +#endif + +/*! + * \brief SCMI Telemetry Management Protocol Definition. + * + * This structure defines the module type and function handlers + * required for SCMI telemetry management. + */ +const struct fwk_module module_scmi_telemetry = { + .api_count = (unsigned int)MOD_SCMI_TELEMETRY_API_COUNT, + .type = FWK_MODULE_TYPE_PROTOCOL, + .init = scmi_telemetry_init, + .bind = scmi_telemetry_bind, + .process_bind_request = scmi_telemetry_process_bind_request, +#if defined(BUILD_HAS_SCMI_NOTIFICATIONS) && defined(BUILD_HAS_NOTIFICATION) + .process_notification = scmi_telemetry_process_notification, +#endif +};